@ably/ui 17.9.0-dev.7b4c6aac → 17.9.1-dev.f8cf1684
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/core/Code.js +1 -1
- package/core/Code.js.map +1 -1
- package/core/CodeSnippet/ApiKeySelector.js +1 -1
- package/core/CodeSnippet/ApiKeySelector.js.map +1 -1
- package/core/CodeSnippet/CopyButton.js +1 -1
- package/core/CodeSnippet/CopyButton.js.map +1 -1
- package/core/CodeSnippet/LanguageSelector.js +1 -1
- package/core/CodeSnippet/LanguageSelector.js.map +1 -1
- package/core/CodeSnippet/PlainCodeView.js +1 -1
- package/core/CodeSnippet/PlainCodeView.js.map +1 -1
- package/core/CodeSnippet/TooltipButton.js +1 -1
- package/core/CodeSnippet/TooltipButton.js.map +1 -1
- package/core/CodeSnippet.js +1 -1
- package/core/CodeSnippet.js.map +1 -1
- package/core/CookieMessage.js +1 -1
- package/core/CookieMessage.js.map +1 -1
- package/core/DropdownMenu.js +1 -1
- package/core/DropdownMenu.js.map +1 -1
- package/core/Expander.js +1 -1
- package/core/Expander.js.map +1 -1
- package/core/Flash.js +1 -1
- package/core/Flash.js.map +1 -1
- package/core/Header/HeaderLinks.js +1 -1
- package/core/Header/HeaderLinks.js.map +1 -1
- package/core/Header.js +1 -1
- package/core/Header.js.map +1 -1
- package/core/Meganav.js +1 -1
- package/core/Meganav.js.map +1 -1
- package/core/Pricing/PricingCards.js +1 -1
- package/core/Pricing/PricingCards.js.map +1 -1
- package/core/Slider.js +1 -1
- package/core/Slider.js.map +1 -1
- package/core/TabMenu.js +1 -1
- package/core/TabMenu.js.map +1 -1
- package/index.d.ts +12 -39
- package/package.json +2 -3
- package/core/utils/useCopyToClipboard.js +0 -2
- package/core/utils/useCopyToClipboard.js.map +0 -1
package/core/DropdownMenu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/DropdownMenu.tsx"],"sourcesContent":["import React, {
|
|
1
|
+
{"version":3,"sources":["../../src/core/DropdownMenu.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useState,\n useEffect,\n useRef,\n ReactNode,\n Dispatch,\n} from \"react\";\nimport Icon from \"./Icon\";\nimport { IconName } from \"./Icon/types\";\nimport cn from \"./utils/cn\";\n\nconst DropdownMenuContext = createContext<{\n isOpen: boolean;\n setOpen: Dispatch<React.SetStateAction<boolean>>;\n}>({\n isOpen: false,\n setOpen: () => {},\n});\n\ntype DropdownMenuProps = {\n /**\n * The content to be displayed within the dropdown menu.\n */\n children: ReactNode;\n};\n\ntype TriggerProps = {\n /**\n * The content to be displayed within the trigger element.\n */\n children: ReactNode;\n /**\n * Additional class names to apply to the trigger element.\n */\n triggerClassNames?: string;\n /**\n * A description for the trigger element, used for accessibility purposes.\n */\n description?: string;\n};\n\ntype ContentProps = {\n /**\n * The content to be displayed within the dropdown menu.\n */\n children: ReactNode;\n /**\n * The position of the dropdown menu relative to the trigger element.\n * Defaults to \"right\".\n */\n anchorPosition?: string;\n /**\n * Additional class names to apply to the content container.\n */\n contentClassNames?: string;\n};\n\ntype LinkProps = {\n url: string;\n title: string;\n subtitle?: string;\n iconName?: IconName;\n children?: ReactNode;\n};\n\nconst DropdownMenu = ({ children }: DropdownMenuProps) => {\n const [isOpen, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const clickHandler = (e: MouseEvent) => {\n if (ref.current?.contains(e.target as Node)) return;\n setOpen(false);\n };\n document.addEventListener(\"click\", clickHandler);\n return () => document.removeEventListener(\"click\", clickHandler);\n }, []);\n\n return (\n <DropdownMenuContext.Provider value={{ isOpen, setOpen }}>\n <div id=\"dropdown-menu\" className=\"relative\" ref={ref}>\n {children}\n </div>\n </DropdownMenuContext.Provider>\n );\n};\n\nconst Trigger = ({\n children,\n triggerClassNames = \"\",\n description,\n}: TriggerProps) => {\n const { isOpen, setOpen } = useContext(DropdownMenuContext);\n\n return (\n <button\n id=\"menu-trigger\"\n aria-label={description}\n onClick={() => setOpen(!isOpen)}\n className={cn(\n \"flex items-center ui-text-label3 font-bold text-neutral-1000 dark:text-neutral-300 focus:outline-none\",\n triggerClassNames,\n )}\n >\n {children}\n <Icon\n name={\n isOpen ? \"icon-gui-chevron-up-mini\" : \"icon-gui-chevron-down-mini\"\n }\n size=\"1.25rem\"\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n />\n </button>\n );\n};\n\nconst Content = ({\n children,\n anchorPosition = \"right\",\n contentClassNames,\n}: ContentProps) => {\n const { isOpen } = useContext(DropdownMenuContext);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <div\n id=\"menu-content\"\n role=\"menu\"\n className={cn(\n \"flex flex-col absolute z-10 border border-neutral-400 dark:border-neutral-900 bg-neutral-000 dark:bg-neutral-1300 rounded-lg ui-shadow-md-soft\",\n anchorPosition === \"right\" ? \"right-0\" : \"left-0\",\n contentClassNames,\n )}\n >\n {children}\n </div>\n );\n};\n\nconst Link = ({ url, title, subtitle, iconName, children }: LinkProps) => {\n return (\n <a\n href={url}\n className=\"menu-link group block p-2 rounded-lg\n hover:bg-neutral-100 dark:hover:bg-neutral-1200 active:bg-neutral-200 dark:active:bg-neutral-1100 text-neutral-1000 dark:text-neutral-300 hover:text-neutral-1300 hover:dark:text-neutral-000\"\n >\n <p className=\"mb-1\">\n {title}\n {iconName ? (\n <Icon\n name={iconName}\n size=\"1rem\"\n additionalCSS=\"align-middle ml-2 relative -top-px -left-1 text-neutral-1300 dark:text-neutral-000\"\n />\n ) : null}\n </p>\n {subtitle ? <p className=\"ui-text-p3 mb-4\">{subtitle}</p> : null}\n {children}\n </a>\n );\n};\n\nDropdownMenu.Trigger = Trigger;\nDropdownMenu.Content = Content;\nDropdownMenu.Link = Link;\n\nexport default DropdownMenu;\n"],"names":["React","createContext","useContext","useState","useEffect","useRef","Icon","cn","DropdownMenuContext","isOpen","setOpen","DropdownMenu","children","ref","clickHandler","e","current","contains","target","document","addEventListener","removeEventListener","Provider","value","div","id","className","Trigger","triggerClassNames","description","button","aria-label","onClick","name","size","additionalCSS","Content","anchorPosition","contentClassNames","role","Link","url","title","subtitle","iconName","a","href","p"],"mappings":"AAAA,OAAOA,OACLC,aAAa,CACbC,UAAU,CACVC,QAAQ,CACRC,SAAS,CACTC,MAAM,KAGD,OAAQ,AACf,QAAOC,SAAU,QAAS,AAE1B,QAAOC,OAAQ,YAAa,CAE5B,MAAMC,oBAAsBP,cAGzB,CACDQ,OAAQ,MACRC,QAAS,KAAO,CAClB,GAgDA,MAAMC,aAAe,CAAC,CAAEC,QAAQ,CAAqB,IACnD,KAAM,CAACH,OAAQC,QAAQ,CAAGP,SAAS,OACnC,MAAMU,IAAMR,OAAuB,MAEnCD,UAAU,KACR,MAAMU,aAAe,AAACC,IACpB,GAAIF,IAAIG,OAAO,EAAEC,SAASF,EAAEG,MAAM,EAAW,OAC7CR,QAAQ,MACV,EACAS,SAASC,gBAAgB,CAAC,QAASN,cACnC,MAAO,IAAMK,SAASE,mBAAmB,CAAC,QAASP,aACrD,EAAG,EAAE,EAEL,OACE,oBAACN,oBAAoBc,QAAQ,EAACC,MAAO,CAAEd,OAAQC,OAAQ,GACrD,oBAACc,OAAIC,GAAG,gBAAgBC,UAAU,WAAWb,IAAKA,KAC/CD,UAIT,EAEA,MAAMe,QAAU,CAAC,CACff,QAAQ,CACRgB,kBAAoB,EAAE,CACtBC,WAAW,CACE,IACb,KAAM,CAAEpB,MAAM,CAAEC,OAAO,CAAE,CAAGR,WAAWM,qBAEvC,OACE,oBAACsB,UACCL,GAAG,eACHM,aAAYF,YACZG,QAAS,IAAMtB,QAAQ,CAACD,QACxBiB,UAAWnB,GACT,wGACAqB,oBAGDhB,SACD,oBAACN,MACC2B,KACExB,OAAS,2BAA6B,6BAExCyB,KAAK,UACLC,cAAc,4CAItB,EAEA,MAAMC,QAAU,CAAC,CACfxB,QAAQ,CACRyB,eAAiB,OAAO,CACxBC,iBAAiB,CACJ,IACb,KAAM,CAAE7B,MAAM,CAAE,CAAGP,WAAWM,qBAE9B,GAAI,CAACC,OAAQ,CACX,OAAO,IACT,CAEA,OACE,oBAACe,OACCC,GAAG,eACHc,KAAK,OACLb,UAAWnB,GACT,iJACA8B,iBAAmB,QAAU,UAAY,SACzCC,oBAGD1B,SAGP,EAEA,MAAM4B,KAAO,CAAC,CAAEC,GAAG,CAAEC,KAAK,CAAEC,QAAQ,CAAEC,QAAQ,CAAEhC,QAAQ,CAAa,IACnE,OACE,oBAACiC,KACCC,KAAML,IACNf,UAAU,sOAGV,oBAACqB,KAAErB,UAAU,QACVgB,MACAE,SACC,oBAACtC,MACC2B,KAAMW,SACNV,KAAK,OACLC,cAAc,uFAEd,MAELQ,SAAW,oBAACI,KAAErB,UAAU,mBAAmBiB,UAAgB,KAC3D/B,SAGP,CAEAD,CAAAA,aAAagB,OAAO,CAAGA,OACvBhB,CAAAA,aAAayB,OAAO,CAAGA,OACvBzB,CAAAA,aAAa6B,IAAI,CAAGA,IAEpB,gBAAe7B,YAAa"}
|
package/core/Expander.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useEffect,useRef,useState}from"react";import*as RadixCollapsible from"@radix-ui/react-collapsible";import{throttle}from"es-toolkit/compat";const Expander=({heightThreshold=200,className,fadeClassName,controlsClassName,controlsOpenedLabel,controlsClosedLabel,children})=>{const innerRef=useRef(null);const[showControls,setShowControls]=useState(false);const[contentHeight,setContentHeight]=useState(heightThreshold);const[expanded,setExpanded]=useState(false);useEffect(()=>{if(innerRef.current){setContentHeight(innerRef.current.clientHeight)}setShowControls(contentHeight>=heightThreshold)},[contentHeight,heightThreshold]);useEffect(()=>{const onResize=throttle(()=>{if(innerRef.current){setContentHeight(innerRef.current.clientHeight)}},250);window.addEventListener("resize",onResize);return()=>{window.removeEventListener("resize",onResize)}},[]);const height=contentHeight<heightThreshold?"auto":expanded?contentHeight:heightThreshold;return React.createElement(RadixCollapsible.Root,{open:expanded,onOpenChange:setExpanded},React.createElement("div",{style:{height},"data-testid":"expander-container",className
|
|
1
|
+
import React,{useEffect,useRef,useState}from"react";import*as RadixCollapsible from"@radix-ui/react-collapsible";import{throttle}from"es-toolkit/compat";import cn from"./utils/cn";const Expander=({heightThreshold=200,className,fadeClassName,controlsClassName,controlsOpenedLabel,controlsClosedLabel,children})=>{const innerRef=useRef(null);const[showControls,setShowControls]=useState(false);const[contentHeight,setContentHeight]=useState(heightThreshold);const[expanded,setExpanded]=useState(false);useEffect(()=>{if(innerRef.current){setContentHeight(innerRef.current.clientHeight)}setShowControls(contentHeight>=heightThreshold)},[contentHeight,heightThreshold]);useEffect(()=>{const onResize=throttle(()=>{if(innerRef.current){setContentHeight(innerRef.current.clientHeight)}},250);window.addEventListener("resize",onResize);return()=>{window.removeEventListener("resize",onResize)}},[]);const height=contentHeight<heightThreshold?"auto":expanded?contentHeight:heightThreshold;return React.createElement(RadixCollapsible.Root,{open:expanded,onOpenChange:setExpanded},React.createElement("div",{style:{height},"data-testid":"expander-container",className:cn("overflow-hidden transition-all relative",className)},showControls&&!expanded&&React.createElement("div",{className:cn("h-16 w-full bg-gradient-to-t from-white to-transparent absolute bottom-0 left-0 right-0",fadeClassName)}),React.createElement("div",{ref:innerRef},children)),showControls&&React.createElement(RadixCollapsible.Trigger,{asChild:true},React.createElement("button",{"data-testid":"expander-controls",className:cn(heightThreshold===0&&!expanded?"":"mt-4","cursor-pointer font-bold text-gui-blue-default-light hover:text-gui-blue-hover-light",controlsClassName)},expanded?controlsOpenedLabel??"View less -":controlsClosedLabel??"View all +")))};export default Expander;
|
|
2
2
|
//# sourceMappingURL=Expander.js.map
|
package/core/Expander.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Expander.tsx"],"sourcesContent":["import React, {\n PropsWithChildren,\n ReactNode,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport * as RadixCollapsible from \"@radix-ui/react-collapsible\";\nimport { throttle } from \"es-toolkit/compat\";\n\ntype ExpanderProps = {\n heightThreshold?: number;\n className?: string;\n fadeClassName?: string;\n controlsClassName?: string;\n controlsOpenedLabel?: string | ReactNode;\n controlsClosedLabel?: string | ReactNode;\n};\n\nconst Expander = ({\n heightThreshold = 200,\n className,\n fadeClassName,\n controlsClassName,\n controlsOpenedLabel,\n controlsClosedLabel,\n children,\n}: PropsWithChildren<ExpanderProps>) => {\n const innerRef = useRef<HTMLDivElement>(null);\n const [showControls, setShowControls] = useState(false);\n const [contentHeight, setContentHeight] = useState<number>(heightThreshold);\n const [expanded, setExpanded] = useState(false);\n\n useEffect(() => {\n if (innerRef.current) {\n setContentHeight(innerRef.current.clientHeight);\n }\n\n setShowControls(contentHeight >= heightThreshold);\n }, [contentHeight, heightThreshold]);\n\n useEffect(() => {\n const onResize = throttle(() => {\n if (innerRef.current) {\n setContentHeight(innerRef.current.clientHeight);\n }\n }, 250);\n\n window.addEventListener(\"resize\", onResize);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, []);\n\n const height =\n contentHeight < heightThreshold\n ? \"auto\"\n : expanded\n ? contentHeight\n : heightThreshold;\n\n return (\n <RadixCollapsible.Root open={expanded} onOpenChange={setExpanded}>\n <div\n style={{ height }}\n data-testid=\"expander-container\"\n className={
|
|
1
|
+
{"version":3,"sources":["../../src/core/Expander.tsx"],"sourcesContent":["import React, {\n PropsWithChildren,\n ReactNode,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport * as RadixCollapsible from \"@radix-ui/react-collapsible\";\nimport { throttle } from \"es-toolkit/compat\";\nimport cn from \"./utils/cn\";\n\ntype ExpanderProps = {\n heightThreshold?: number;\n className?: string;\n fadeClassName?: string;\n controlsClassName?: string;\n controlsOpenedLabel?: string | ReactNode;\n controlsClosedLabel?: string | ReactNode;\n};\n\nconst Expander = ({\n heightThreshold = 200,\n className,\n fadeClassName,\n controlsClassName,\n controlsOpenedLabel,\n controlsClosedLabel,\n children,\n}: PropsWithChildren<ExpanderProps>) => {\n const innerRef = useRef<HTMLDivElement>(null);\n const [showControls, setShowControls] = useState(false);\n const [contentHeight, setContentHeight] = useState<number>(heightThreshold);\n const [expanded, setExpanded] = useState(false);\n\n useEffect(() => {\n if (innerRef.current) {\n setContentHeight(innerRef.current.clientHeight);\n }\n\n setShowControls(contentHeight >= heightThreshold);\n }, [contentHeight, heightThreshold]);\n\n useEffect(() => {\n const onResize = throttle(() => {\n if (innerRef.current) {\n setContentHeight(innerRef.current.clientHeight);\n }\n }, 250);\n\n window.addEventListener(\"resize\", onResize);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, []);\n\n const height =\n contentHeight < heightThreshold\n ? \"auto\"\n : expanded\n ? contentHeight\n : heightThreshold;\n\n return (\n <RadixCollapsible.Root open={expanded} onOpenChange={setExpanded}>\n <div\n style={{ height }}\n data-testid=\"expander-container\"\n className={cn(\"overflow-hidden transition-all relative\", className)}\n >\n {showControls && !expanded && (\n <div\n className={cn(\n \"h-16 w-full bg-gradient-to-t from-white to-transparent absolute bottom-0 left-0 right-0\",\n fadeClassName,\n )}\n ></div>\n )}\n <div ref={innerRef}>{children}</div>\n </div>\n {showControls && (\n <RadixCollapsible.Trigger asChild>\n <button\n data-testid=\"expander-controls\"\n className={cn(\n heightThreshold === 0 && !expanded ? \"\" : \"mt-4\",\n \"cursor-pointer font-bold text-gui-blue-default-light hover:text-gui-blue-hover-light\",\n controlsClassName,\n )}\n >\n {expanded\n ? (controlsOpenedLabel ?? \"View less -\")\n : (controlsClosedLabel ?? \"View all +\")}\n </button>\n </RadixCollapsible.Trigger>\n )}\n </RadixCollapsible.Root>\n );\n};\n\nexport default Expander;\n"],"names":["React","useEffect","useRef","useState","RadixCollapsible","throttle","cn","Expander","heightThreshold","className","fadeClassName","controlsClassName","controlsOpenedLabel","controlsClosedLabel","children","innerRef","showControls","setShowControls","contentHeight","setContentHeight","expanded","setExpanded","current","clientHeight","onResize","window","addEventListener","removeEventListener","height","Root","open","onOpenChange","div","style","data-testid","ref","Trigger","asChild","button"],"mappings":"AAAA,OAAOA,OAGLC,SAAS,CACTC,MAAM,CACNC,QAAQ,KACH,OAAQ,AACf,WAAYC,qBAAsB,6BAA8B,AAChE,QAASC,QAAQ,KAAQ,mBAAoB,AAC7C,QAAOC,OAAQ,YAAa,CAW5B,MAAMC,SAAW,CAAC,CAChBC,gBAAkB,GAAG,CACrBC,SAAS,CACTC,aAAa,CACbC,iBAAiB,CACjBC,mBAAmB,CACnBC,mBAAmB,CACnBC,QAAQ,CACyB,IACjC,MAAMC,SAAWb,OAAuB,MACxC,KAAM,CAACc,aAAcC,gBAAgB,CAAGd,SAAS,OACjD,KAAM,CAACe,cAAeC,iBAAiB,CAAGhB,SAAiBK,iBAC3D,KAAM,CAACY,SAAUC,YAAY,CAAGlB,SAAS,OAEzCF,UAAU,KACR,GAAIc,SAASO,OAAO,CAAE,CACpBH,iBAAiBJ,SAASO,OAAO,CAACC,YAAY,CAChD,CAEAN,gBAAgBC,eAAiBV,gBACnC,EAAG,CAACU,cAAeV,gBAAgB,EAEnCP,UAAU,KACR,MAAMuB,SAAWnB,SAAS,KACxB,GAAIU,SAASO,OAAO,CAAE,CACpBH,iBAAiBJ,SAASO,OAAO,CAACC,YAAY,CAChD,CACF,EAAG,KAEHE,OAAOC,gBAAgB,CAAC,SAAUF,UAClC,MAAO,KACLC,OAAOE,mBAAmB,CAAC,SAAUH,SACvC,CACF,EAAG,EAAE,EAEL,MAAMI,OACJV,cAAgBV,gBACZ,OACAY,SACEF,cACAV,gBAER,OACE,oBAACJ,iBAAiByB,IAAI,EAACC,KAAMV,SAAUW,aAAcV,aACnD,oBAACW,OACCC,MAAO,CAAEL,MAAO,EAChBM,cAAY,qBACZzB,UAAWH,GAAG,0CAA2CG,YAExDO,cAAgB,CAACI,UAChB,oBAACY,OACCvB,UAAWH,GACT,0FACAI,iBAIN,oBAACsB,OAAIG,IAAKpB,UAAWD,WAEtBE,cACC,oBAACZ,iBAAiBgC,OAAO,EAACC,QAAAA,MACxB,oBAACC,UACCJ,cAAY,oBACZzB,UAAWH,GACTE,kBAAoB,GAAK,CAACY,SAAW,GAAK,OAC1C,uFACAT,oBAGDS,SACIR,qBAAuB,cACvBC,qBAAuB,eAMxC,CAEA,gBAAeN,QAAS"}
|
package/core/Flash.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useEffect,useState,useRef}from"react";import DOMPurify from"dompurify";import{getRemoteDataStore}from"./remote-data-store.js";import ConnectStateWrapper from"./ConnectStateWrapper";import Icon from"./Icon";const REDUCER_KEY="flashes";const FLASH_DATA_ID="ui-flashes";const initialState={items:[]};const reducerFlashes={[REDUCER_KEY]:(state=initialState,action)=>{switch(action.type){case"flash/push":{const flashes=Array.isArray(action.payload)?action.payload:[action.payload];return{items:[...state.items,...flashes]}}default:return state}}};const selectFlashes=store=>store.getState()[REDUCER_KEY];const FLASH_BG_COLOR={error:"bg-gui-error",success:"bg-zingy-green",notice:"bg-electric-cyan",info:"bg-electric-cyan",alert:"bg-active-orange"};const FLASH_TEXT_COLOR={error:"text-white",success:"text-cool-black",notice:"text-cool-black",info:"text-cool-black",alert:"text-white"};const AUTO_HIDE=["success","info","notice"];const AUTO_HIDE_TIME=8e3;const useAutoHide=(type,closeFlash)=>{const timeoutId=useRef(null);useEffect(()=>{if(AUTO_HIDE.includes(type)){timeoutId.current=setTimeout(()=>{closeFlash()},AUTO_HIDE_TIME)}return()=>{if(timeoutId.current){clearTimeout(timeoutId.current)}}},[type,closeFlash])};const Flash=({id,type,content,removeFlash})=>{const ref=useRef(null);const[closed,setClosed]=useState(false);const[flashHeight,setFlashHeight]=useState(0);const
|
|
1
|
+
import React,{useEffect,useState,useRef}from"react";import DOMPurify from"dompurify";import{getRemoteDataStore}from"./remote-data-store.js";import ConnectStateWrapper from"./ConnectStateWrapper";import Icon from"./Icon";const REDUCER_KEY="flashes";const FLASH_DATA_ID="ui-flashes";const initialState={items:[]};const reducerFlashes={[REDUCER_KEY]:(state=initialState,action)=>{switch(action.type){case"flash/push":{const flashes=Array.isArray(action.payload)?action.payload:[action.payload];return{items:[...state.items,...flashes]}}default:return state}}};const selectFlashes=store=>store.getState()[REDUCER_KEY];const FLASH_BG_COLOR={error:"bg-gui-error",success:"bg-zingy-green",notice:"bg-electric-cyan",info:"bg-electric-cyan",alert:"bg-active-orange"};const FLASH_TEXT_COLOR={error:"text-white",success:"text-cool-black",notice:"text-cool-black",info:"text-cool-black",alert:"text-white"};const AUTO_HIDE=["success","info","notice"];const AUTO_HIDE_TIME=8e3;const useAutoHide=(type,closeFlash)=>{const timeoutId=useRef(null);useEffect(()=>{if(AUTO_HIDE.includes(type)){timeoutId.current=setTimeout(()=>{closeFlash()},AUTO_HIDE_TIME)}return()=>{if(timeoutId.current){clearTimeout(timeoutId.current)}}},[type,closeFlash])};const Flash=({id,type,content,removeFlash})=>{const ref=useRef(null);const[closed,setClosed]=useState(false);const[flashHeight,setFlashHeight]=useState(0);const closeFlash=()=>{if(ref.current){setFlashHeight(ref.current.getBoundingClientRect().height)}setClosed(true);setTimeout(()=>{if(id){removeFlash(id)}},100)};useAutoHide(type,closeFlash);const animateEntry=!closed;let style;if(flashHeight&&!closed){style={height:`${flashHeight}px`}}else if(closed){style={height:0,marginTop:0,zIndex:-1}}else{style={}}const safeContent=DOMPurify.sanitize(content,{ALLOWED_TAGS:["a"],ALLOWED_ATTR:["href","data-method"],ALLOWED_URI_REGEXP:/^\/[^/]/});const withIcons={notice:"icon-gui-ably-badge",success:"icon-gui-check-outline",error:"icon-gui-exclamation-triangle-outline",alert:"icon-gui-exclamation-triangle-outline",info:""};const iconColor={notice:"text-cool-black",success:"text-cool-black",error:"text-white",alert:"text-white",info:""};return React.createElement("div",{className:`ui-flash-message ui-grid-px ${animateEntry?"ui-flash-message-enter":""}`,style:style,ref:ref,"data-id":"ui-flash","data-testid":"ui-flash"},React.createElement("div",{className:`${FLASH_BG_COLOR[type]} p-8 flex align-center rounded shadow-container-subtle`},withIcons[type]&&iconColor[type]&&React.createElement(Icon,{name:withIcons[type],color:iconColor[type],size:"1.5rem",additionalCSS:"mr-4 self-baseline"}),React.createElement("p",{className:`ui-text-p1 mr-4 ${FLASH_TEXT_COLOR[type]}`,dangerouslySetInnerHTML:{__html:safeContent}}),React.createElement("button",{type:"button",className:"p-0 ml-auto self-start focus:outline-none",onClick:closeFlash},iconColor[type]&&React.createElement(Icon,{name:"icon-gui-x-mark-outline",color:iconColor[type],size:"1.5rem",additionalCSS:"transition-colors"}))))};const Flashes=({flashes})=>{const[flashesWithIds,setFlashesWithIds]=useState([]);const removeFlash=flashId=>setFlashesWithIds(items=>items.filter(item=>item.id!==flashId));useEffect(()=>{if(!flashes?.items?.length)return;setFlashesWithIds(state=>{const newFlashes=(flashes.items??[]).filter(flash=>!state.some(existing=>existing.content===flash.content&&existing.type===flash.type)).map(flash=>({...flash,id:Math.random().toString(36).slice(2),removed:false,removeFlash}));return newFlashes.length>0?[...state,...newFlashes]:state})},[flashes]);return React.createElement("div",{className:"ui-flash","data-id":FLASH_DATA_ID},flashesWithIds.filter(item=>!item.removed).map(flash=>React.createElement(Flash,{key:flash.id,...flash})))};const BackendFlashes=({flashes})=>{useEffect(()=>{const transformedFlashes=flashes.map(flash=>{const[type,content]=flash;return{type,content}})||[];if(transformedFlashes.length>0){const store=getRemoteDataStore();store.dispatch({type:"flash/push",payload:transformedFlashes})}},[flashes]);const WrappedFlashes=ConnectStateWrapper(Flashes,{flashes:selectFlashes});return React.createElement(WrappedFlashes,null)};export{reducerFlashes,FLASH_DATA_ID,Flashes};export default BackendFlashes;
|
|
2
2
|
//# sourceMappingURL=Flash.js.map
|
package/core/Flash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Flash.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef } from \"react\";\nimport DOMPurify from \"dompurify\";\nimport { getRemoteDataStore } from \"./remote-data-store.js\";\nimport ConnectStateWrapper from \"./ConnectStateWrapper\";\nimport Icon from \"./Icon\";\nimport { ColorClass } from \"./styles/colors/types\";\nimport { IconName } from \"./Icon/types\";\n\ntype FlashPropsType = \"error\" | \"success\" | \"notice\" | \"info\" | \"alert\";\n\ntype FlashProps = {\n id: string;\n removed: boolean;\n type: FlashPropsType;\n content: string;\n removeFlash: (id: string) => void;\n};\n\ntype FlashesProps = {\n flashes: { items: Pick<FlashProps, \"type\" | \"content\">[] };\n};\n\ntype BackendFlashesProps = {\n flashes: string[][];\n};\n\nconst REDUCER_KEY = \"flashes\";\nconst FLASH_DATA_ID = \"ui-flashes\";\n\nconst initialState = { items: [] };\n\nconst reducerFlashes = {\n [REDUCER_KEY]: (\n state: {\n items: FlashProps[];\n } = initialState,\n action: { type: string; payload: FlashProps | FlashProps[] },\n ) => {\n switch (action.type) {\n case \"flash/push\": {\n const flashes = Array.isArray(action.payload)\n ? action.payload\n : [action.payload];\n return { items: [...state.items, ...flashes] };\n }\n default:\n return state;\n }\n },\n};\n\n// Not cool but redux isn't a long term plan here\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst selectFlashes = (store: any): { items: FlashProps[] } =>\n store.getState()[REDUCER_KEY];\n\nconst FLASH_BG_COLOR = {\n error: \"bg-gui-error\",\n success: \"bg-zingy-green\",\n notice: \"bg-electric-cyan\",\n info: \"bg-electric-cyan\",\n alert: \"bg-active-orange\",\n};\n\nconst FLASH_TEXT_COLOR = {\n error: \"text-white\",\n success: \"text-cool-black\",\n notice: \"text-cool-black\",\n info: \"text-cool-black\",\n alert: \"text-white\",\n};\n\nconst AUTO_HIDE = [\"success\", \"info\", \"notice\"];\nconst AUTO_HIDE_TIME = 8000;\n\nconst useAutoHide = (type: string, closeFlash: () => void) => {\n const timeoutId = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (AUTO_HIDE.includes(type)) {\n timeoutId.current = setTimeout(() => {\n closeFlash();\n }, AUTO_HIDE_TIME);\n }\n\n return () => {\n if (timeoutId.current) {\n clearTimeout(timeoutId.current);\n }\n };\n }, [type, closeFlash]);\n};\n\nconst Flash = ({ id, type, content, removeFlash }: FlashProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const [closed, setClosed] = useState(false);\n const [flashHeight, setFlashHeight] = useState(0);\n const [triggerEntryAnimation, setTriggerEntryAnimation] = useState(false);\n\n const closeFlash = () => {\n if (ref.current) {\n setFlashHeight(ref.current.getBoundingClientRect().height);\n }\n\n setClosed(true);\n\n setTimeout(() => {\n if (id) {\n removeFlash(id);\n }\n }, 100);\n };\n\n useEffect(() => setTriggerEntryAnimation(true), []);\n useAutoHide(type, closeFlash);\n\n const animateEntry = triggerEntryAnimation && !closed;\n\n let style;\n\n if (flashHeight && !closed) {\n style = { height: `${flashHeight}px` };\n } else if (closed) {\n style = { height: 0, marginTop: 0, zIndex: -1 };\n } else {\n style = {};\n }\n\n const safeContent = DOMPurify.sanitize(content, {\n ALLOWED_TAGS: [\"a\"],\n ALLOWED_ATTR: [\"href\", \"data-method\"],\n ALLOWED_URI_REGEXP: /^\\/[^/]/,\n });\n\n const withIcons: Record<FlashPropsType, IconName | \"\"> = {\n notice: \"icon-gui-ably-badge\",\n success: \"icon-gui-check-outline\",\n error: \"icon-gui-exclamation-triangle-outline\",\n alert: \"icon-gui-exclamation-triangle-outline\",\n info: \"\",\n };\n\n const iconColor: Record<FlashPropsType, ColorClass | \"\"> = {\n notice: \"text-cool-black\",\n success: \"text-cool-black\",\n error: \"text-white\",\n alert: \"text-white\",\n info: \"\",\n };\n\n return (\n <div\n className={`ui-flash-message ui-grid-px ${\n animateEntry ? \"ui-flash-message-enter\" : \"\"\n }`}\n style={style}\n ref={ref}\n data-id=\"ui-flash\"\n data-testid=\"ui-flash\"\n >\n <div\n className={`${FLASH_BG_COLOR[type]} p-8 flex align-center rounded shadow-container-subtle`}\n >\n {withIcons[type] && iconColor[type] && (\n <Icon\n name={withIcons[type]}\n color={iconColor[type]}\n size=\"1.5rem\"\n additionalCSS=\"mr-4 self-baseline\"\n />\n )}\n <p\n className={`ui-text-p1 mr-4 ${FLASH_TEXT_COLOR[type]}`}\n dangerouslySetInnerHTML={{ __html: safeContent }}\n />\n <button\n type=\"button\"\n className=\"p-0 ml-auto self-start focus:outline-none\"\n onClick={closeFlash}\n >\n {iconColor[type] && (\n <Icon\n name=\"icon-gui-x-mark-outline\"\n color={iconColor[type]}\n size=\"1.5rem\"\n additionalCSS=\"transition-colors\"\n />\n )}\n </button>\n </div>\n </div>\n );\n};\n\nconst Flashes = ({ flashes }: FlashesProps) => {\n const [flashesWithIds, setFlashesWithIds] = useState<FlashProps[]>([]);\n\n const removeFlash = (flashId: string) =>\n setFlashesWithIds((items) => items.filter((item) => item.id !== flashId));\n\n useEffect(() => {\n setFlashesWithIds((state) => {\n return [\n ...state,\n ...(flashes?.items ?? []).map((flash) => ({\n ...flash,\n id: Math.random().toString(36).slice(2),\n removed: false,\n removeFlash,\n })),\n ];\n });\n }, [flashes]);\n\n return (\n <div className=\"ui-flash\" data-id={FLASH_DATA_ID}>\n {flashesWithIds\n .filter((item) => !item.removed)\n .map((flash) => (\n <Flash key={flash.id} {...flash} />\n ))}\n </div>\n );\n};\n\nconst BackendFlashes = ({ flashes }: BackendFlashesProps) => {\n useEffect(() => {\n const transformedFlashes =\n flashes.map((flash) => {\n const [type, content] = flash;\n return { type, content };\n }) || [];\n\n if (transformedFlashes.length > 0) {\n const store = getRemoteDataStore();\n\n store.dispatch({\n type: \"flash/push\",\n payload: transformedFlashes,\n });\n }\n }, [flashes]);\n\n const WrappedFlashes = ConnectStateWrapper(Flashes, {\n flashes: selectFlashes,\n });\n\n return <WrappedFlashes />;\n};\n\nexport { reducerFlashes, FLASH_DATA_ID, Flashes };\nexport default BackendFlashes;\n"],"names":["React","useEffect","useState","useRef","DOMPurify","getRemoteDataStore","ConnectStateWrapper","Icon","REDUCER_KEY","FLASH_DATA_ID","initialState","items","reducerFlashes","state","action","type","flashes","Array","isArray","payload","selectFlashes","store","getState","FLASH_BG_COLOR","error","success","notice","info","alert","FLASH_TEXT_COLOR","AUTO_HIDE","AUTO_HIDE_TIME","useAutoHide","closeFlash","timeoutId","includes","current","setTimeout","clearTimeout","Flash","id","content","removeFlash","ref","closed","setClosed","flashHeight","setFlashHeight","triggerEntryAnimation","setTriggerEntryAnimation","getBoundingClientRect","height","animateEntry","style","marginTop","zIndex","safeContent","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","ALLOWED_URI_REGEXP","withIcons","iconColor","div","className","data-id","data-testid","name","color","size","additionalCSS","p","dangerouslySetInnerHTML","__html","button","onClick","Flashes","flashesWithIds","setFlashesWithIds","flashId","filter","item","map","flash","Math","random","toString","slice","removed","key","BackendFlashes","transformedFlashes","length","dispatch","WrappedFlashes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/Flash.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef } from \"react\";\nimport DOMPurify from \"dompurify\";\nimport { getRemoteDataStore } from \"./remote-data-store.js\";\nimport ConnectStateWrapper from \"./ConnectStateWrapper\";\nimport Icon from \"./Icon\";\nimport { ColorClass } from \"./styles/colors/types\";\nimport { IconName } from \"./Icon/types\";\n\ntype FlashPropsType = \"error\" | \"success\" | \"notice\" | \"info\" | \"alert\";\n\ntype FlashProps = {\n id: string;\n removed: boolean;\n type: FlashPropsType;\n content: string;\n removeFlash: (id: string) => void;\n};\n\ntype FlashesProps = {\n flashes: { items: Pick<FlashProps, \"type\" | \"content\">[] };\n};\n\ntype BackendFlashesProps = {\n flashes: string[][];\n};\n\nconst REDUCER_KEY = \"flashes\";\nconst FLASH_DATA_ID = \"ui-flashes\";\n\nconst initialState = { items: [] };\n\nconst reducerFlashes = {\n [REDUCER_KEY]: (\n state: {\n items: FlashProps[];\n } = initialState,\n action: { type: string; payload: FlashProps | FlashProps[] },\n ) => {\n switch (action.type) {\n case \"flash/push\": {\n const flashes = Array.isArray(action.payload)\n ? action.payload\n : [action.payload];\n return { items: [...state.items, ...flashes] };\n }\n default:\n return state;\n }\n },\n};\n\n// Not cool but redux isn't a long term plan here\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst selectFlashes = (store: any): { items: FlashProps[] } =>\n store.getState()[REDUCER_KEY];\n\nconst FLASH_BG_COLOR = {\n error: \"bg-gui-error\",\n success: \"bg-zingy-green\",\n notice: \"bg-electric-cyan\",\n info: \"bg-electric-cyan\",\n alert: \"bg-active-orange\",\n};\n\nconst FLASH_TEXT_COLOR = {\n error: \"text-white\",\n success: \"text-cool-black\",\n notice: \"text-cool-black\",\n info: \"text-cool-black\",\n alert: \"text-white\",\n};\n\nconst AUTO_HIDE = [\"success\", \"info\", \"notice\"];\nconst AUTO_HIDE_TIME = 8000;\n\nconst useAutoHide = (type: string, closeFlash: () => void) => {\n const timeoutId = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (AUTO_HIDE.includes(type)) {\n timeoutId.current = setTimeout(() => {\n closeFlash();\n }, AUTO_HIDE_TIME);\n }\n\n return () => {\n if (timeoutId.current) {\n clearTimeout(timeoutId.current);\n }\n };\n }, [type, closeFlash]);\n};\n\nconst Flash = ({ id, type, content, removeFlash }: FlashProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const [closed, setClosed] = useState(false);\n const [flashHeight, setFlashHeight] = useState(0);\n\n const closeFlash = () => {\n if (ref.current) {\n setFlashHeight(ref.current.getBoundingClientRect().height);\n }\n\n setClosed(true);\n\n setTimeout(() => {\n if (id) {\n removeFlash(id);\n }\n }, 100);\n };\n\n useAutoHide(type, closeFlash);\n\n const animateEntry = !closed;\n\n let style;\n\n if (flashHeight && !closed) {\n style = { height: `${flashHeight}px` };\n } else if (closed) {\n style = { height: 0, marginTop: 0, zIndex: -1 };\n } else {\n style = {};\n }\n\n const safeContent = DOMPurify.sanitize(content, {\n ALLOWED_TAGS: [\"a\"],\n ALLOWED_ATTR: [\"href\", \"data-method\"],\n ALLOWED_URI_REGEXP: /^\\/[^/]/,\n });\n\n const withIcons: Record<FlashPropsType, IconName | \"\"> = {\n notice: \"icon-gui-ably-badge\",\n success: \"icon-gui-check-outline\",\n error: \"icon-gui-exclamation-triangle-outline\",\n alert: \"icon-gui-exclamation-triangle-outline\",\n info: \"\",\n };\n\n const iconColor: Record<FlashPropsType, ColorClass | \"\"> = {\n notice: \"text-cool-black\",\n success: \"text-cool-black\",\n error: \"text-white\",\n alert: \"text-white\",\n info: \"\",\n };\n\n return (\n <div\n className={`ui-flash-message ui-grid-px ${\n animateEntry ? \"ui-flash-message-enter\" : \"\"\n }`}\n style={style}\n ref={ref}\n data-id=\"ui-flash\"\n data-testid=\"ui-flash\"\n >\n <div\n className={`${FLASH_BG_COLOR[type]} p-8 flex align-center rounded shadow-container-subtle`}\n >\n {withIcons[type] && iconColor[type] && (\n <Icon\n name={withIcons[type]}\n color={iconColor[type]}\n size=\"1.5rem\"\n additionalCSS=\"mr-4 self-baseline\"\n />\n )}\n <p\n className={`ui-text-p1 mr-4 ${FLASH_TEXT_COLOR[type]}`}\n dangerouslySetInnerHTML={{ __html: safeContent }}\n />\n <button\n type=\"button\"\n className=\"p-0 ml-auto self-start focus:outline-none\"\n onClick={closeFlash}\n >\n {iconColor[type] && (\n <Icon\n name=\"icon-gui-x-mark-outline\"\n color={iconColor[type]}\n size=\"1.5rem\"\n additionalCSS=\"transition-colors\"\n />\n )}\n </button>\n </div>\n </div>\n );\n};\n\nconst Flashes = ({ flashes }: FlashesProps) => {\n const [flashesWithIds, setFlashesWithIds] = useState<FlashProps[]>([]);\n\n const removeFlash = (flashId: string) =>\n setFlashesWithIds((items) => items.filter((item) => item.id !== flashId));\n\n useEffect(() => {\n if (!flashes?.items?.length) return;\n\n setFlashesWithIds((state) => {\n const newFlashes = (flashes.items ?? [])\n .filter(\n (flash) =>\n !state.some(\n (existing) =>\n existing.content === flash.content &&\n existing.type === flash.type,\n ),\n )\n .map((flash) => ({\n ...flash,\n id: Math.random().toString(36).slice(2),\n removed: false,\n removeFlash,\n }));\n\n return newFlashes.length > 0 ? [...state, ...newFlashes] : state;\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [flashes]);\n\n return (\n <div className=\"ui-flash\" data-id={FLASH_DATA_ID}>\n {flashesWithIds\n .filter((item) => !item.removed)\n .map((flash) => (\n <Flash key={flash.id} {...flash} />\n ))}\n </div>\n );\n};\n\nconst BackendFlashes = ({ flashes }: BackendFlashesProps) => {\n useEffect(() => {\n const transformedFlashes =\n flashes.map((flash) => {\n const [type, content] = flash;\n return { type, content };\n }) || [];\n\n if (transformedFlashes.length > 0) {\n const store = getRemoteDataStore();\n\n store.dispatch({\n type: \"flash/push\",\n payload: transformedFlashes,\n });\n }\n }, [flashes]);\n\n const WrappedFlashes = ConnectStateWrapper(Flashes, {\n flashes: selectFlashes,\n });\n\n return <WrappedFlashes />;\n};\n\nexport { reducerFlashes, FLASH_DATA_ID, Flashes };\nexport default BackendFlashes;\n"],"names":["React","useEffect","useState","useRef","DOMPurify","getRemoteDataStore","ConnectStateWrapper","Icon","REDUCER_KEY","FLASH_DATA_ID","initialState","items","reducerFlashes","state","action","type","flashes","Array","isArray","payload","selectFlashes","store","getState","FLASH_BG_COLOR","error","success","notice","info","alert","FLASH_TEXT_COLOR","AUTO_HIDE","AUTO_HIDE_TIME","useAutoHide","closeFlash","timeoutId","includes","current","setTimeout","clearTimeout","Flash","id","content","removeFlash","ref","closed","setClosed","flashHeight","setFlashHeight","getBoundingClientRect","height","animateEntry","style","marginTop","zIndex","safeContent","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","ALLOWED_URI_REGEXP","withIcons","iconColor","div","className","data-id","data-testid","name","color","size","additionalCSS","p","dangerouslySetInnerHTML","__html","button","onClick","Flashes","flashesWithIds","setFlashesWithIds","flashId","filter","item","length","newFlashes","flash","some","existing","map","Math","random","toString","slice","removed","key","BackendFlashes","transformedFlashes","dispatch","WrappedFlashes"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useRef}from"react";import Icon from"../Icon";import LinkButton from"../LinkButton";import cn from"../utils/cn";import DropdownMenu from"../DropdownMenu";const testSessionState={signedIn:false,logOut:{token:"0000",href:"accounts/sign_out"},accountName:"Ably"};export const HeaderLinks=({sessionState=testSessionState,headerLinks,searchButtonVisibility,searchButton,className})=>{const{signedIn,logOut}=sessionState;const formRef=useRef(null);const headerLinkClasses="ui-text-label2 md:ui-text-label3 !font-bold py-4 text-neutral-1300 dark:text-neutral-000 md:text-neutral-1000 dark:md:text-neutral-300 hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-1300 dark:active:text-neutral-000 transition-colors";const dropdownMenuLinkClasses="block p-2 ui-text-label3 font-semibold text-neutral-1000 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-1200 active:bg-neutral-200 dark:active:bg-neutral-1100 rounded-lg";const onClickLogout=e=>{e.preventDefault();formRef.current?.submit()};const DashboardLink=({className})=>React.createElement("a",{href:"/dashboard",className:className},"Dashboard");const LogoutForm=React.createElement("form",{ref:formRef,method:"post",action:logOut.href,className:"hidden"},React.createElement("input",{name:"_method",value:"delete",type:"hidden"}),React.createElement("input",{name:"authenticity_token",value:logOut.token,type:"hidden"}));return React.createElement("nav",{className:cn("flex md:flex-1 md:items-center md:justify-end flex-col md:flex-row border-t-[1px] border-neutral-300 md:border-t-0 md:gap-4 pt-3 pb-4 md:py-0",className)},signedIn&&React.createElement(React.Fragment,null,LogoutForm,React.createElement("div",{className:"block md:hidden"},React.createElement("div",{className:"flex flex-col border-b-[1px] border-neutral-300 px-4 pb-3 mb-3"},React.createElement("span",{className:"py-3 ui-text-sub-header text-[18px] text-neutral-700 dark:text-neutral-600 font-bold"},sessionState.accountName),React.createElement(DashboardLink,{className:headerLinkClasses})))),headerLinks?.map(({href,label,external})=>React.createElement("a",{key:href,className:cn(headerLinkClasses,"flex items-center gap-1.5 px-4 md:px-0 leading-none"),href:href,target:external?"_blank":undefined,rel:external?"noreferrer noopener":undefined},label,external&&React.createElement(Icon,{name:"icon-gui-arrow-top-right-on-square-mini",size:"20px"}))),searchButtonVisibility!=="mobile"?searchButton:null,signedIn?React.createElement(React.Fragment,null,React.createElement("div",{className:"hidden md:block relative"},React.createElement(DropdownMenu,null,React.createElement(DropdownMenu.Trigger,{description:`Account menu for ${sessionState.accountName}`},React.createElement("span",{className:"block text-ellipsis overflow-hidden whitespace-nowrap w-full max-w-[9.375rem] leading-normal"},sessionState.accountName)),React.createElement(DropdownMenu.Content,{anchorPosition:"right",contentClassNames:"w-60 mt-3"},React.createElement("div",{className:"p-2"},React.createElement(DashboardLink,{className:dropdownMenuLinkClasses}),React.createElement("button",{onClick:onClickLogout,className:dropdownMenuLinkClasses},"Logout"))))),React.createElement("div",{className:"block md:hidden px-4 pt-4 pb-0"},React.createElement(LinkButton,{onClick:onClickLogout,variant:"secondary",className:"w-full md:ui-button-secondary-xs","aria-label":"Logout",rightIcon:"icon-gui-arrow-right-end-on-rectangle-outline"},"Logout"))):React.createElement("div",{className:"flex gap-3 pt-3 md:py-0 px-4 md:px-0"},React.createElement(LinkButton,{href:"/login",variant:"secondary",className:"flex-1 md:flex-none md:ui-button-secondary-xs hover:text-neutral-1300 dark:hover:text-neutral-000"},"Login"),React.createElement(LinkButton,{href:"/sign-up",variant:"primary",className:"flex-1 md:flex-none md:ui-button-primary-xs hover:text-neutral-000 dark:hover:text-neutral-1300"},"Start free")))};
|
|
1
|
+
import React,{useRef,useMemo}from"react";import Icon from"../Icon";import LinkButton from"../LinkButton";import cn from"../utils/cn";import DropdownMenu from"../DropdownMenu";const testSessionState={signedIn:false,logOut:{token:"0000",href:"accounts/sign_out"},accountName:"Ably"};export const HeaderLinks=({sessionState=testSessionState,headerLinks,searchButtonVisibility,searchButton,className})=>{const{signedIn,logOut}=sessionState;const formRef=useRef(null);const headerLinkClasses="ui-text-label2 md:ui-text-label3 !font-bold py-4 text-neutral-1300 dark:text-neutral-000 md:text-neutral-1000 dark:md:text-neutral-300 hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-1300 dark:active:text-neutral-000 transition-colors";const dropdownMenuLinkClasses="block p-2 ui-text-label3 font-semibold text-neutral-1000 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-1200 active:bg-neutral-200 dark:active:bg-neutral-1100 rounded-lg";const onClickLogout=e=>{e.preventDefault();formRef.current?.submit()};const DashboardLink=({className})=>useMemo(()=>React.createElement("a",{href:"/dashboard",className:className},"Dashboard"),[className]);const LogoutForm=React.createElement("form",{ref:formRef,method:"post",action:logOut.href,className:"hidden"},React.createElement("input",{name:"_method",value:"delete",type:"hidden"}),React.createElement("input",{name:"authenticity_token",value:logOut.token,type:"hidden"}));return React.createElement("nav",{className:cn("flex md:flex-1 md:items-center md:justify-end flex-col md:flex-row border-t-[1px] border-neutral-300 md:border-t-0 md:gap-4 pt-3 pb-4 md:py-0",className)},signedIn&&React.createElement(React.Fragment,null,LogoutForm,React.createElement("div",{className:"block md:hidden"},React.createElement("div",{className:"flex flex-col border-b-[1px] border-neutral-300 px-4 pb-3 mb-3"},React.createElement("span",{className:"py-3 ui-text-sub-header text-[18px] text-neutral-700 dark:text-neutral-600 font-bold"},sessionState.accountName),React.createElement(DashboardLink,{className:headerLinkClasses})))),headerLinks?.map(({href,label,external})=>React.createElement("a",{key:href,className:cn(headerLinkClasses,"flex items-center gap-1.5 px-4 md:px-0 leading-none"),href:href,target:external?"_blank":undefined,rel:external?"noreferrer noopener":undefined},label,external&&React.createElement(Icon,{name:"icon-gui-arrow-top-right-on-square-mini",size:"20px"}))),searchButtonVisibility!=="mobile"?searchButton:null,signedIn?React.createElement(React.Fragment,null,React.createElement("div",{className:"hidden md:block relative"},React.createElement(DropdownMenu,null,React.createElement(DropdownMenu.Trigger,{description:`Account menu for ${sessionState.accountName}`},React.createElement("span",{className:"block text-ellipsis overflow-hidden whitespace-nowrap w-full max-w-[9.375rem] leading-normal"},sessionState.accountName)),React.createElement(DropdownMenu.Content,{anchorPosition:"right",contentClassNames:"w-60 mt-3"},React.createElement("div",{className:"p-2"},React.createElement(DashboardLink,{className:dropdownMenuLinkClasses}),React.createElement("button",{onClick:onClickLogout,className:dropdownMenuLinkClasses},"Logout"))))),React.createElement("div",{className:"block md:hidden px-4 pt-4 pb-0"},React.createElement(LinkButton,{onClick:onClickLogout,variant:"secondary",className:"w-full md:ui-button-secondary-xs","aria-label":"Logout",rightIcon:"icon-gui-arrow-right-end-on-rectangle-outline"},"Logout"))):React.createElement("div",{className:"flex gap-3 pt-3 md:py-0 px-4 md:px-0"},React.createElement(LinkButton,{href:"/login",variant:"secondary",className:"flex-1 md:flex-none md:ui-button-secondary-xs hover:text-neutral-1300 dark:hover:text-neutral-000"},"Login"),React.createElement(LinkButton,{href:"/sign-up",variant:"primary",className:"flex-1 md:flex-none md:ui-button-primary-xs hover:text-neutral-000 dark:hover:text-neutral-1300"},"Start free")))};
|
|
2
2
|
//# sourceMappingURL=HeaderLinks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/Header/HeaderLinks.tsx"],"sourcesContent":["import React, { MouseEvent, useRef } from \"react\";\nimport { HeaderProps } from \"../Header\";\nimport Icon from \"../Icon\";\nimport LinkButton from \"../LinkButton\";\nimport cn from \"../utils/cn\";\nimport DropdownMenu from \"../DropdownMenu\";\n\nconst testSessionState = {\n signedIn: false,\n logOut: {\n token: \"0000\",\n href: \"accounts/sign_out\",\n },\n accountName: \"Ably\",\n};\n\nexport const HeaderLinks: React.FC<\n Pick<\n HeaderProps,\n | \"sessionState\"\n | \"headerLinks\"\n | \"searchButtonVisibility\"\n | \"searchButton\"\n | \"className\"\n >\n> = ({\n sessionState = testSessionState,\n headerLinks,\n searchButtonVisibility,\n searchButton,\n className,\n}) => {\n const { signedIn, logOut } = sessionState;\n const formRef = useRef<HTMLFormElement>(null);\n\n const headerLinkClasses =\n \"ui-text-label2 md:ui-text-label3 !font-bold py-4 text-neutral-1300 dark:text-neutral-000 md:text-neutral-1000 dark:md:text-neutral-300 hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-1300 dark:active:text-neutral-000 transition-colors\";\n\n const dropdownMenuLinkClasses =\n \"block p-2 ui-text-label3 font-semibold text-neutral-1000 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-1200 active:bg-neutral-200 dark:active:bg-neutral-1100 rounded-lg\";\n\n const onClickLogout = (e: MouseEvent) => {\n e.preventDefault();\n formRef.current?.submit();\n };\n\n const DashboardLink = ({ className }: { className: string }) => (\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/Header/HeaderLinks.tsx"],"sourcesContent":["import React, { MouseEvent, useRef, useMemo } from \"react\";\nimport { HeaderProps } from \"../Header\";\nimport Icon from \"../Icon\";\nimport LinkButton from \"../LinkButton\";\nimport cn from \"../utils/cn\";\nimport DropdownMenu from \"../DropdownMenu\";\n\nconst testSessionState = {\n signedIn: false,\n logOut: {\n token: \"0000\",\n href: \"accounts/sign_out\",\n },\n accountName: \"Ably\",\n};\n\nexport const HeaderLinks: React.FC<\n Pick<\n HeaderProps,\n | \"sessionState\"\n | \"headerLinks\"\n | \"searchButtonVisibility\"\n | \"searchButton\"\n | \"className\"\n >\n> = ({\n sessionState = testSessionState,\n headerLinks,\n searchButtonVisibility,\n searchButton,\n className,\n}) => {\n const { signedIn, logOut } = sessionState;\n const formRef = useRef<HTMLFormElement>(null);\n\n const headerLinkClasses =\n \"ui-text-label2 md:ui-text-label3 !font-bold py-4 text-neutral-1300 dark:text-neutral-000 md:text-neutral-1000 dark:md:text-neutral-300 hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-1300 dark:active:text-neutral-000 transition-colors\";\n\n const dropdownMenuLinkClasses =\n \"block p-2 ui-text-label3 font-semibold text-neutral-1000 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-1200 active:bg-neutral-200 dark:active:bg-neutral-1100 rounded-lg\";\n\n const onClickLogout = (e: MouseEvent) => {\n e.preventDefault();\n formRef.current?.submit();\n };\n\n const DashboardLink = ({ className }: { className: string }) =>\n useMemo(\n () => (\n <a href=\"/dashboard\" className={className}>\n Dashboard\n </a>\n ),\n [className],\n );\n\n const LogoutForm = (\n <form ref={formRef} method=\"post\" action={logOut.href} className=\"hidden\">\n <input name=\"_method\" value=\"delete\" type=\"hidden\" />\n <input name=\"authenticity_token\" value={logOut.token} type=\"hidden\" />\n </form>\n );\n\n return (\n <nav\n className={cn(\n \"flex md:flex-1 md:items-center md:justify-end flex-col md:flex-row border-t-[1px] border-neutral-300 md:border-t-0 md:gap-4 pt-3 pb-4 md:py-0\",\n className,\n )}\n >\n {signedIn && (\n <>\n {LogoutForm}\n <div className=\"block md:hidden\">\n <div className=\"flex flex-col border-b-[1px] border-neutral-300 px-4 pb-3 mb-3\">\n <span className=\"py-3 ui-text-sub-header text-[18px] text-neutral-700 dark:text-neutral-600 font-bold\">\n {sessionState.accountName}\n </span>\n {<DashboardLink className={headerLinkClasses} />}\n </div>\n </div>\n </>\n )}\n\n {headerLinks?.map(({ href, label, external }) => (\n <a\n key={href}\n className={cn(\n headerLinkClasses,\n \"flex items-center gap-1.5 px-4 md:px-0 leading-none\",\n )}\n href={href}\n target={external ? \"_blank\" : undefined}\n rel={external ? \"noreferrer noopener\" : undefined}\n >\n {label}\n {external && (\n <Icon name=\"icon-gui-arrow-top-right-on-square-mini\" size=\"20px\" />\n )}\n </a>\n ))}\n\n {searchButtonVisibility !== \"mobile\" ? searchButton : null}\n {signedIn ? (\n <>\n <div className=\"hidden md:block relative\">\n <DropdownMenu>\n <DropdownMenu.Trigger\n description={`Account menu for ${sessionState.accountName}`}\n >\n <span className=\"block text-ellipsis overflow-hidden whitespace-nowrap w-full max-w-[9.375rem] leading-normal\">\n {sessionState.accountName}\n </span>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content\n anchorPosition=\"right\"\n contentClassNames=\"w-60 mt-3\"\n >\n <div className=\"p-2\">\n <DashboardLink className={dropdownMenuLinkClasses} />\n <button\n onClick={onClickLogout}\n className={dropdownMenuLinkClasses}\n >\n Logout\n </button>\n </div>\n </DropdownMenu.Content>\n </DropdownMenu>\n </div>\n <div className=\"block md:hidden px-4 pt-4 pb-0\">\n <LinkButton\n onClick={onClickLogout}\n variant=\"secondary\"\n className=\"w-full md:ui-button-secondary-xs\"\n aria-label=\"Logout\"\n rightIcon=\"icon-gui-arrow-right-end-on-rectangle-outline\"\n >\n Logout\n </LinkButton>\n </div>\n </>\n ) : (\n <div className=\"flex gap-3 pt-3 md:py-0 px-4 md:px-0\">\n <LinkButton\n href=\"/login\"\n variant=\"secondary\"\n className=\"flex-1 md:flex-none md:ui-button-secondary-xs hover:text-neutral-1300 dark:hover:text-neutral-000\"\n >\n Login\n </LinkButton>\n <LinkButton\n href=\"/sign-up\"\n variant=\"primary\"\n className=\"flex-1 md:flex-none md:ui-button-primary-xs hover:text-neutral-000 dark:hover:text-neutral-1300\"\n >\n Start free\n </LinkButton>\n </div>\n )}\n </nav>\n );\n};\n"],"names":["React","useRef","useMemo","Icon","LinkButton","cn","DropdownMenu","testSessionState","signedIn","logOut","token","href","accountName","HeaderLinks","sessionState","headerLinks","searchButtonVisibility","searchButton","className","formRef","headerLinkClasses","dropdownMenuLinkClasses","onClickLogout","e","preventDefault","current","submit","DashboardLink","a","LogoutForm","form","ref","method","action","input","name","value","type","nav","div","span","map","label","external","key","target","undefined","rel","size","Trigger","description","Content","anchorPosition","contentClassNames","button","onClick","variant","aria-label","rightIcon"],"mappings":"AAAA,OAAOA,OAAqBC,MAAM,CAAEC,OAAO,KAAQ,OAAQ,AAE3D,QAAOC,SAAU,SAAU,AAC3B,QAAOC,eAAgB,eAAgB,AACvC,QAAOC,OAAQ,aAAc,AAC7B,QAAOC,iBAAkB,iBAAkB,CAE3C,MAAMC,iBAAmB,CACvBC,SAAU,MACVC,OAAQ,CACNC,MAAO,OACPC,KAAM,mBACR,EACAC,YAAa,MACf,CAEA,QAAO,MAAMC,YAST,CAAC,CACHC,aAAeP,gBAAgB,CAC/BQ,WAAW,CACXC,sBAAsB,CACtBC,YAAY,CACZC,SAAS,CACV,IACC,KAAM,CAAEV,QAAQ,CAAEC,MAAM,CAAE,CAAGK,aAC7B,MAAMK,QAAUlB,OAAwB,MAExC,MAAMmB,kBACJ,qQAEF,MAAMC,wBACJ,8LAEF,MAAMC,cAAgB,AAACC,IACrBA,EAAEC,cAAc,EAChBL,CAAAA,QAAQM,OAAO,EAAEC,QACnB,EAEA,MAAMC,cAAgB,CAAC,CAAET,SAAS,CAAyB,GACzDhB,QACE,IACE,oBAAC0B,KAAEjB,KAAK,aAAaO,UAAWA,WAAW,aAI7C,CAACA,UAAU,EAGf,MAAMW,WACJ,oBAACC,QAAKC,IAAKZ,QAASa,OAAO,OAAOC,OAAQxB,OAAOE,IAAI,CAAEO,UAAU,UAC/D,oBAACgB,SAAMC,KAAK,UAAUC,MAAM,SAASC,KAAK,WAC1C,oBAACH,SAAMC,KAAK,qBAAqBC,MAAO3B,OAAOC,KAAK,CAAE2B,KAAK,YAI/D,OACE,oBAACC,OACCpB,UAAWb,GACT,gJACAa,YAGDV,UACC,wCACGqB,WACD,oBAACU,OAAIrB,UAAU,mBACb,oBAACqB,OAAIrB,UAAU,kEACb,oBAACsB,QAAKtB,UAAU,wFACbJ,aAAaF,WAAW,EAE1B,oBAACe,eAAcT,UAAWE,uBAMlCL,aAAa0B,IAAI,CAAC,CAAE9B,IAAI,CAAE+B,KAAK,CAAEC,QAAQ,CAAE,GAC1C,oBAACf,KACCgB,IAAKjC,KACLO,UAAWb,GACTe,kBACA,uDAEFT,KAAMA,KACNkC,OAAQF,SAAW,SAAWG,UAC9BC,IAAKJ,SAAW,sBAAwBG,WAEvCJ,MACAC,UACC,oBAACxC,MAAKgC,KAAK,0CAA0Ca,KAAK,WAK/DhC,yBAA2B,SAAWC,aAAe,KACrDT,SACC,wCACE,oBAAC+B,OAAIrB,UAAU,4BACb,oBAACZ,kBACC,oBAACA,aAAa2C,OAAO,EACnBC,YAAa,CAAC,iBAAiB,EAAEpC,aAAaF,WAAW,CAAC,CAAC,EAE3D,oBAAC4B,QAAKtB,UAAU,gGACbJ,aAAaF,WAAW,GAG7B,oBAACN,aAAa6C,OAAO,EACnBC,eAAe,QACfC,kBAAkB,aAElB,oBAACd,OAAIrB,UAAU,OACb,oBAACS,eAAcT,UAAWG,0BAC1B,oBAACiC,UACCC,QAASjC,cACTJ,UAAWG,yBACZ,cAOT,oBAACkB,OAAIrB,UAAU,kCACb,oBAACd,YACCmD,QAASjC,cACTkC,QAAQ,YACRtC,UAAU,mCACVuC,aAAW,SACXC,UAAU,iDACX,YAML,oBAACnB,OAAIrB,UAAU,wCACb,oBAACd,YACCO,KAAK,SACL6C,QAAQ,YACRtC,UAAU,qGACX,SAGD,oBAACd,YACCO,KAAK,WACL6C,QAAQ,UACRtC,UAAU,mGACX,eAOX,CAAE"}
|
package/core/Header.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useState,useEffect,useRef,useMemo,useCallback}from"react";import Icon from"./Icon";import cn from"./utils/cn";import Logo from"./Logo";import{componentMaxHeight,HEADER_BOTTOM_MARGIN,HEADER_HEIGHT}from"./utils/heights";import{HeaderLinks}from"./Header/HeaderLinks";import{throttle}from"es-toolkit/compat";import{COLLAPSE_TRIGGER_DISTANCE}from"./Notice/component";const FLEXIBLE_DESKTOP_CLASSES="hidden md:flex flex-1 items-center h-full";const MAX_MOBILE_MENU_WIDTH="560px";const Header=({className,isNoticeBannerEnabled=false,noticeHeight=0,searchBar,searchButton,logoHref,headerLinks,headerLinksClassName,headerCenterClassName,nav,mobileNav,sessionState,themedScrollpoints=[],searchButtonVisibility="all",location,logoBadge})=>{const[showMenu,setShowMenu]=useState(false);const[fadingOut,setFadingOut]=useState(false);const[noticeBannerVisible,setNoticeBannerVisible]=useState(isNoticeBannerEnabled);const menuRef=useRef(null);const[scrollpointClasses,setScrollpointClasses]=useState(themedScrollpoints.length>0?themedScrollpoints[0].className:"");const headerStyle={height:HEADER_HEIGHT,top:noticeBannerVisible?`${noticeHeight}px`:"0"};const headerClassName=cn("fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-all duration-300 ease-in-out px-6 lg:px-16",scrollpointClasses,{"md:top-auto":noticeBannerVisible});const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};const handleNoticeClose=useCallback(()=>{setNoticeBannerVisible(false)},[]);useEffect(()=>{document.addEventListener("notice-closed",handleNoticeClose);return()=>document.removeEventListener("notice-closed",handleNoticeClose)},[handleNoticeClose]);useEffect(()=>{const handleScroll=()=>{const noticeElement=document.querySelector('[data-id="ui-notice"]');const isNoticeClosedToBeHidden=noticeElement?.classList.contains("ui-announcement-hidden");setNoticeBannerVisible(window.scrollY<=COLLAPSE_TRIGGER_DISTANCE&&isNoticeBannerEnabled&&!isNoticeClosedToBeHidden);for(const scrollpoint of themedScrollpoints){const element=document.getElementById(scrollpoint.id);if(element){const rect=element.getBoundingClientRect();if(rect.top<=HEADER_HEIGHT&&rect.bottom>=HEADER_HEIGHT){setScrollpointClasses(scrollpoint.className);return}}}};const throttledHandleScroll=throttle(handleScroll,100);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints,isNoticeBannerEnabled]);useEffect(()=>{const handleResize=()=>{if(window.innerWidth>=1040){setShowMenu(false)}};window.addEventListener("resize",handleResize);return()=>window.removeEventListener("resize",handleResize)},[]);useEffect(()=>{if(showMenu){document.body.classList.add("overflow-hidden")}else{document.body.classList.remove("overflow-hidden")}return()=>{document.body.classList.remove("overflow-hidden")}},[showMenu]);useEffect(()=>{if(location&&showMenu){closeMenu()}},[location
|
|
1
|
+
import React,{useState,useEffect,useRef,useMemo,useCallback}from"react";import Icon from"./Icon";import cn from"./utils/cn";import Logo from"./Logo";import{componentMaxHeight,HEADER_BOTTOM_MARGIN,HEADER_HEIGHT}from"./utils/heights";import{HeaderLinks}from"./Header/HeaderLinks";import{throttle}from"es-toolkit/compat";import{COLLAPSE_TRIGGER_DISTANCE}from"./Notice/component";const FLEXIBLE_DESKTOP_CLASSES="hidden md:flex flex-1 items-center h-full";const MAX_MOBILE_MENU_WIDTH="560px";const Header=({className,isNoticeBannerEnabled=false,noticeHeight=0,searchBar,searchButton,logoHref,headerLinks,headerLinksClassName,headerCenterClassName,nav,mobileNav,sessionState,themedScrollpoints=[],searchButtonVisibility="all",location,logoBadge})=>{const[showMenu,setShowMenu]=useState(false);const[fadingOut,setFadingOut]=useState(false);const[noticeBannerVisible,setNoticeBannerVisible]=useState(isNoticeBannerEnabled);const menuRef=useRef(null);const[scrollpointClasses,setScrollpointClasses]=useState(themedScrollpoints.length>0?themedScrollpoints[0].className:"");const headerStyle={height:HEADER_HEIGHT,top:noticeBannerVisible?`${noticeHeight}px`:"0"};const headerClassName=cn("fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-all duration-300 ease-in-out px-6 lg:px-16",scrollpointClasses,{"md:top-auto":noticeBannerVisible});const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};const handleNoticeClose=useCallback(()=>{setNoticeBannerVisible(false)},[]);useEffect(()=>{document.addEventListener("notice-closed",handleNoticeClose);return()=>document.removeEventListener("notice-closed",handleNoticeClose)},[handleNoticeClose]);useEffect(()=>{const handleScroll=()=>{const noticeElement=document.querySelector('[data-id="ui-notice"]');const isNoticeClosedToBeHidden=noticeElement?.classList.contains("ui-announcement-hidden");setNoticeBannerVisible(window.scrollY<=COLLAPSE_TRIGGER_DISTANCE&&isNoticeBannerEnabled&&!isNoticeClosedToBeHidden);for(const scrollpoint of themedScrollpoints){const element=document.getElementById(scrollpoint.id);if(element){const rect=element.getBoundingClientRect();if(rect.top<=HEADER_HEIGHT&&rect.bottom>=HEADER_HEIGHT){setScrollpointClasses(scrollpoint.className);return}}}};const throttledHandleScroll=throttle(handleScroll,100);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints,isNoticeBannerEnabled]);useEffect(()=>{const handleResize=()=>{if(window.innerWidth>=1040){setShowMenu(false)}};window.addEventListener("resize",handleResize);return()=>window.removeEventListener("resize",handleResize)},[]);useEffect(()=>{if(showMenu){document.body.classList.add("overflow-hidden")}else{document.body.classList.remove("overflow-hidden")}return()=>{document.body.classList.remove("overflow-hidden")}},[showMenu]);useEffect(()=>{if(location&&showMenu){closeMenu()}},[location]);const wrappedSearchButton=useMemo(()=>searchButton?React.createElement("div",{className:"text-neutral-1300 dark:text-neutral-000 flex items-center"},searchButton):null,[searchButton]);return React.createElement(React.Fragment,null,React.createElement("header",{role:"banner",style:headerStyle,className:headerClassName},React.createElement("div",{className:cn("flex items-center h-full",className)},React.createElement("nav",{className:"flex flex-1 h-full items-center"},["light","dark"].map(theme=>React.createElement(Logo,{key:theme,href:logoHref,theme:theme,badge:logoBadge,additionalLinkAttrs:{className:cn("h-full focus-base rounded mr-4 lg:mr-8",{"flex dark:hidden":theme==="light","hidden dark:flex":theme==="dark"})}})),React.createElement("div",{className:FLEXIBLE_DESKTOP_CLASSES},nav)),React.createElement("div",{className:"flex md:hidden flex-1 items-center justify-end gap-6 h-full"},searchButtonVisibility!=="desktop"?wrappedSearchButton:null,React.createElement("button",{className:"cursor-pointer focus-base rounded flex items-center p-0",onClick:()=>setShowMenu(!showMenu),"aria-expanded":showMenu,"aria-controls":"mobile-menu","aria-label":"Toggle menu"},React.createElement(Icon,{name:showMenu?"icon-gui-x-mark-outline":"icon-gui-bars-3-outline",additionalCSS:"text-neutral-1300 dark:text-neutral-000",size:"1.5rem"}))),searchBar?React.createElement("div",{className:cn(FLEXIBLE_DESKTOP_CLASSES,"justify-center",headerCenterClassName)},searchBar):null,React.createElement(HeaderLinks,{className:cn(FLEXIBLE_DESKTOP_CLASSES,headerLinksClassName),headerLinks:headerLinks,sessionState:sessionState,searchButton:wrappedSearchButton,searchButtonVisibility:searchButtonVisibility}))),showMenu?React.createElement(React.Fragment,null,React.createElement("div",{className:cn("fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40",{"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]":!fadingOut,"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]":fadingOut}),onClick:closeMenu,onKeyDown:e=>e.key==="Escape"&&closeMenu(),role:"presentation"}),React.createElement("div",{id:"mobile-menu",className:"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50",style:{maxWidth:MAX_MOBILE_MENU_WIDTH,maxHeight:componentMaxHeight(HEADER_HEIGHT,HEADER_BOTTOM_MARGIN)},ref:menuRef,role:"navigation"},mobileNav,React.createElement(HeaderLinks,{headerLinks:headerLinks,sessionState:sessionState}))):null)};export default Header;
|
|
2
2
|
//# sourceMappingURL=Header.js.map
|
package/core/Header.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Header.tsx"],"sourcesContent":["import React, {\n useState,\n useEffect,\n useRef,\n ReactNode,\n useMemo,\n useCallback,\n} from \"react\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn\";\nimport Logo from \"./Logo\";\nimport {\n componentMaxHeight,\n HEADER_BOTTOM_MARGIN,\n HEADER_HEIGHT,\n} from \"./utils/heights\";\nimport { HeaderLinks } from \"./Header/HeaderLinks\";\nimport { throttle } from \"es-toolkit/compat\";\nimport { Theme } from \"./styles/colors/types\";\nimport { COLLAPSE_TRIGGER_DISTANCE } from \"./Notice/component\";\n\nexport type ThemedScrollpoint = {\n id: string;\n className: string;\n};\n\n/**\n * Represents the state of the user session in the header.\n */\nexport type HeaderSessionState = {\n /**\n * Indicates if the user is signed in.\n */\n signedIn: boolean;\n\n /**\n * Information required to log out the user.\n */\n logOut: {\n /**\n * Token used for logging out.\n */\n token: string;\n\n /**\n * URL to log out the user.\n */\n href: string;\n };\n\n /**\n * Name of the user's account.\n */\n accountName: string;\n};\n\n/**\n * Props for the Header component.\n */\nexport type HeaderProps = {\n /**\n * Optional classnames to add to the header\n */\n className?: string;\n /**\n * Indicates if the notice banner is enabled.\n */\n isNoticeBannerEnabled?: boolean;\n /**\n * Height of the notice banner in pixels.\n */\n noticeHeight?: number;\n /**\n * Optional search bar element.\n */\n searchBar?: ReactNode;\n\n /**\n * Optional search button element.\n */\n searchButton?: ReactNode;\n\n /**\n * URL for the logo link.\n */\n logoHref?: string;\n\n /**\n * Array of header links.\n */\n headerLinks?: {\n /**\n * URL for the link.\n */\n href: string;\n\n /**\n * Label for the link.\n */\n label: string;\n\n /**\n * Indicates if the link should open in a new tab.\n */\n external?: boolean;\n }[];\n\n /**\n * Optional classname for styling the header links container.\n */\n headerLinksClassName?: string;\n\n /**\n * Optional classname for styling the header center container.\n */\n headerCenterClassName?: string;\n\n /**\n * Optional desktop navigation element.\n */\n nav?: ReactNode;\n\n /**\n * Optional mobile navigation element.\n */\n mobileNav?: ReactNode;\n\n /**\n * State of the user session.\n */\n sessionState?: HeaderSessionState;\n\n /**\n * Array of themed scrollpoints. The header will change its appearance based on the scrollpoint in view.\n */\n themedScrollpoints?: ThemedScrollpoint[];\n\n /**\n * Visibility setting for the search button.\n * - \"all\": Visible on all devices.\n * - \"desktop\": Visible only on desktop devices.\n * - \"mobile\": Visible only on mobile devices.\n */\n searchButtonVisibility?: \"all\" | \"desktop\" | \"mobile\";\n\n /**\n * Optional location object to detect location changes.\n */\n location?: Location;\n\n /**\n * Optional badge text to display on the logo.\n */\n logoBadge?: string;\n};\n\nconst FLEXIBLE_DESKTOP_CLASSES = \"hidden md:flex flex-1 items-center h-full\";\n\n/**\n * Maximum width before the menu expanded into full width\n */\nconst MAX_MOBILE_MENU_WIDTH = \"560px\";\n\nconst Header: React.FC<HeaderProps> = ({\n className,\n isNoticeBannerEnabled = false,\n noticeHeight = 0,\n searchBar,\n searchButton,\n logoHref,\n headerLinks,\n headerLinksClassName,\n headerCenterClassName,\n nav,\n mobileNav,\n sessionState,\n themedScrollpoints = [],\n searchButtonVisibility = \"all\",\n location,\n logoBadge,\n}) => {\n const [showMenu, setShowMenu] = useState(false);\n const [fadingOut, setFadingOut] = useState(false);\n const [noticeBannerVisible, setNoticeBannerVisible] = useState(\n isNoticeBannerEnabled,\n );\n const menuRef = useRef<HTMLDivElement>(null);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\n themedScrollpoints.length > 0 ? themedScrollpoints[0].className : \"\",\n );\n\n const headerStyle = {\n height: HEADER_HEIGHT,\n top: noticeBannerVisible ? `${noticeHeight}px` : \"0\",\n };\n\n const headerClassName = cn(\n \"fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-all duration-300 ease-in-out px-6 lg:px-16\",\n scrollpointClasses,\n {\n \"md:top-auto\": noticeBannerVisible,\n },\n );\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n const handleNoticeClose = useCallback(() => {\n setNoticeBannerVisible(false);\n }, []);\n\n useEffect(() => {\n document.addEventListener(\"notice-closed\", handleNoticeClose);\n return () =>\n document.removeEventListener(\"notice-closed\", handleNoticeClose);\n }, [handleNoticeClose]);\n\n useEffect(() => {\n const handleScroll = () => {\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n const isNoticeClosedToBeHidden = noticeElement?.classList.contains(\n \"ui-announcement-hidden\",\n );\n setNoticeBannerVisible(\n window.scrollY <= COLLAPSE_TRIGGER_DISTANCE &&\n isNoticeBannerEnabled &&\n !isNoticeClosedToBeHidden,\n );\n for (const scrollpoint of themedScrollpoints) {\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT) {\n setScrollpointClasses(scrollpoint.className);\n return;\n }\n }\n }\n };\n\n const throttledHandleScroll = throttle(handleScroll, 100);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints, isNoticeBannerEnabled]);\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth >= 1040) {\n setShowMenu(false);\n }\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n if (showMenu) {\n document.body.classList.add(\"overflow-hidden\");\n } else {\n document.body.classList.remove(\"overflow-hidden\");\n }\n\n // Cleanup on unmount\n return () => {\n document.body.classList.remove(\"overflow-hidden\");\n };\n }, [showMenu]);\n\n // Close menu when location changes\n useEffect(() => {\n if (location && showMenu) {\n closeMenu();\n }\n }, [location, showMenu]);\n\n const wrappedSearchButton = useMemo(\n () =>\n searchButton ? (\n <div className=\"text-neutral-1300 dark:text-neutral-000 flex items-center\">\n {searchButton}\n </div>\n ) : null,\n [searchButton],\n );\n\n return (\n <>\n <header role=\"banner\" style={headerStyle} className={headerClassName}>\n <div className={cn(\"flex items-center h-full\", className)}>\n <nav className=\"flex flex-1 h-full items-center\">\n {([\"light\", \"dark\"] as Theme[]).map((theme) => (\n <Logo\n key={theme}\n href={logoHref}\n theme={theme}\n badge={logoBadge}\n additionalLinkAttrs={{\n className: cn(\"h-full focus-base rounded mr-4 lg:mr-8\", {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n }),\n }}\n />\n ))}\n <div className={FLEXIBLE_DESKTOP_CLASSES}>{nav}</div>\n </nav>\n <div className=\"flex md:hidden flex-1 items-center justify-end gap-6 h-full\">\n {searchButtonVisibility !== \"desktop\" ? wrappedSearchButton : null}\n <button\n className=\"cursor-pointer focus-base rounded flex items-center p-0\"\n onClick={() => setShowMenu(!showMenu)}\n aria-expanded={showMenu}\n aria-controls=\"mobile-menu\"\n aria-label=\"Toggle menu\"\n >\n <Icon\n name={\n showMenu\n ? \"icon-gui-x-mark-outline\"\n : \"icon-gui-bars-3-outline\"\n }\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n size=\"1.5rem\"\n />\n </button>\n </div>\n {searchBar ? (\n <div\n className={cn(\n FLEXIBLE_DESKTOP_CLASSES,\n \"justify-center\",\n headerCenterClassName,\n )}\n >\n {searchBar}\n </div>\n ) : null}\n <HeaderLinks\n className={cn(FLEXIBLE_DESKTOP_CLASSES, headerLinksClassName)}\n headerLinks={headerLinks}\n sessionState={sessionState}\n searchButton={wrappedSearchButton}\n searchButtonVisibility={searchButtonVisibility}\n />\n </div>\n </header>\n {showMenu ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40\",\n {\n \"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]\":\n !fadingOut,\n \"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]\":\n fadingOut,\n },\n )}\n onClick={closeMenu}\n onKeyDown={(e) => e.key === \"Escape\" && closeMenu()}\n role=\"presentation\"\n />\n <div\n id=\"mobile-menu\"\n className=\"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50\"\n style={{\n maxWidth: MAX_MOBILE_MENU_WIDTH,\n maxHeight: componentMaxHeight(\n HEADER_HEIGHT,\n HEADER_BOTTOM_MARGIN,\n ),\n }}\n ref={menuRef}\n role=\"navigation\"\n >\n {mobileNav}\n <HeaderLinks\n headerLinks={headerLinks}\n sessionState={sessionState}\n />\n </div>\n </>\n ) : null}\n </>\n );\n};\n\nexport default Header;\n"],"names":["React","useState","useEffect","useRef","useMemo","useCallback","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","COLLAPSE_TRIGGER_DISTANCE","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","className","isNoticeBannerEnabled","noticeHeight","searchBar","searchButton","logoHref","headerLinks","headerLinksClassName","headerCenterClassName","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","location","logoBadge","showMenu","setShowMenu","fadingOut","setFadingOut","noticeBannerVisible","setNoticeBannerVisible","menuRef","scrollpointClasses","setScrollpointClasses","length","headerStyle","height","top","headerClassName","closeMenu","setTimeout","handleNoticeClose","document","addEventListener","removeEventListener","handleScroll","noticeElement","querySelector","isNoticeClosedToBeHidden","classList","contains","window","scrollY","scrollpoint","element","getElementById","id","rect","getBoundingClientRect","bottom","throttledHandleScroll","handleResize","innerWidth","body","add","remove","wrappedSearchButton","div","header","role","style","map","theme","key","href","badge","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxWidth","maxHeight","ref"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/Header.tsx"],"sourcesContent":["import React, {\n useState,\n useEffect,\n useRef,\n ReactNode,\n useMemo,\n useCallback,\n} from \"react\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn\";\nimport Logo from \"./Logo\";\nimport {\n componentMaxHeight,\n HEADER_BOTTOM_MARGIN,\n HEADER_HEIGHT,\n} from \"./utils/heights\";\nimport { HeaderLinks } from \"./Header/HeaderLinks\";\nimport { throttle } from \"es-toolkit/compat\";\nimport { Theme } from \"./styles/colors/types\";\nimport { COLLAPSE_TRIGGER_DISTANCE } from \"./Notice/component\";\n\nexport type ThemedScrollpoint = {\n id: string;\n className: string;\n};\n\n/**\n * Represents the state of the user session in the header.\n */\nexport type HeaderSessionState = {\n /**\n * Indicates if the user is signed in.\n */\n signedIn: boolean;\n\n /**\n * Information required to log out the user.\n */\n logOut: {\n /**\n * Token used for logging out.\n */\n token: string;\n\n /**\n * URL to log out the user.\n */\n href: string;\n };\n\n /**\n * Name of the user's account.\n */\n accountName: string;\n};\n\n/**\n * Props for the Header component.\n */\nexport type HeaderProps = {\n /**\n * Optional classnames to add to the header\n */\n className?: string;\n /**\n * Indicates if the notice banner is enabled.\n */\n isNoticeBannerEnabled?: boolean;\n /**\n * Height of the notice banner in pixels.\n */\n noticeHeight?: number;\n /**\n * Optional search bar element.\n */\n searchBar?: ReactNode;\n\n /**\n * Optional search button element.\n */\n searchButton?: ReactNode;\n\n /**\n * URL for the logo link.\n */\n logoHref?: string;\n\n /**\n * Array of header links.\n */\n headerLinks?: {\n /**\n * URL for the link.\n */\n href: string;\n\n /**\n * Label for the link.\n */\n label: string;\n\n /**\n * Indicates if the link should open in a new tab.\n */\n external?: boolean;\n }[];\n\n /**\n * Optional classname for styling the header links container.\n */\n headerLinksClassName?: string;\n\n /**\n * Optional classname for styling the header center container.\n */\n headerCenterClassName?: string;\n\n /**\n * Optional desktop navigation element.\n */\n nav?: ReactNode;\n\n /**\n * Optional mobile navigation element.\n */\n mobileNav?: ReactNode;\n\n /**\n * State of the user session.\n */\n sessionState?: HeaderSessionState;\n\n /**\n * Array of themed scrollpoints. The header will change its appearance based on the scrollpoint in view.\n */\n themedScrollpoints?: ThemedScrollpoint[];\n\n /**\n * Visibility setting for the search button.\n * - \"all\": Visible on all devices.\n * - \"desktop\": Visible only on desktop devices.\n * - \"mobile\": Visible only on mobile devices.\n */\n searchButtonVisibility?: \"all\" | \"desktop\" | \"mobile\";\n\n /**\n * Optional location object to detect location changes.\n */\n location?: Location;\n\n /**\n * Optional badge text to display on the logo.\n */\n logoBadge?: string;\n};\n\nconst FLEXIBLE_DESKTOP_CLASSES = \"hidden md:flex flex-1 items-center h-full\";\n\n/**\n * Maximum width before the menu expanded into full width\n */\nconst MAX_MOBILE_MENU_WIDTH = \"560px\";\n\nconst Header: React.FC<HeaderProps> = ({\n className,\n isNoticeBannerEnabled = false,\n noticeHeight = 0,\n searchBar,\n searchButton,\n logoHref,\n headerLinks,\n headerLinksClassName,\n headerCenterClassName,\n nav,\n mobileNav,\n sessionState,\n themedScrollpoints = [],\n searchButtonVisibility = \"all\",\n location,\n logoBadge,\n}) => {\n const [showMenu, setShowMenu] = useState(false);\n const [fadingOut, setFadingOut] = useState(false);\n const [noticeBannerVisible, setNoticeBannerVisible] = useState(\n isNoticeBannerEnabled,\n );\n const menuRef = useRef<HTMLDivElement>(null);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\n themedScrollpoints.length > 0 ? themedScrollpoints[0].className : \"\",\n );\n\n const headerStyle = {\n height: HEADER_HEIGHT,\n top: noticeBannerVisible ? `${noticeHeight}px` : \"0\",\n };\n\n const headerClassName = cn(\n \"fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-all duration-300 ease-in-out px-6 lg:px-16\",\n scrollpointClasses,\n {\n \"md:top-auto\": noticeBannerVisible,\n },\n );\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n const handleNoticeClose = useCallback(() => {\n setNoticeBannerVisible(false);\n }, []);\n\n useEffect(() => {\n document.addEventListener(\"notice-closed\", handleNoticeClose);\n return () =>\n document.removeEventListener(\"notice-closed\", handleNoticeClose);\n }, [handleNoticeClose]);\n\n useEffect(() => {\n const handleScroll = () => {\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n const isNoticeClosedToBeHidden = noticeElement?.classList.contains(\n \"ui-announcement-hidden\",\n );\n setNoticeBannerVisible(\n window.scrollY <= COLLAPSE_TRIGGER_DISTANCE &&\n isNoticeBannerEnabled &&\n !isNoticeClosedToBeHidden,\n );\n for (const scrollpoint of themedScrollpoints) {\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT) {\n setScrollpointClasses(scrollpoint.className);\n return;\n }\n }\n }\n };\n\n const throttledHandleScroll = throttle(handleScroll, 100);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints, isNoticeBannerEnabled]);\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth >= 1040) {\n setShowMenu(false);\n }\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n if (showMenu) {\n document.body.classList.add(\"overflow-hidden\");\n } else {\n document.body.classList.remove(\"overflow-hidden\");\n }\n\n // Cleanup on unmount\n return () => {\n document.body.classList.remove(\"overflow-hidden\");\n };\n }, [showMenu]);\n\n // Close menu when location changes\n useEffect(() => {\n if (location && showMenu) {\n closeMenu();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [location]);\n\n const wrappedSearchButton = useMemo(\n () =>\n searchButton ? (\n <div className=\"text-neutral-1300 dark:text-neutral-000 flex items-center\">\n {searchButton}\n </div>\n ) : null,\n [searchButton],\n );\n\n return (\n <>\n <header role=\"banner\" style={headerStyle} className={headerClassName}>\n <div className={cn(\"flex items-center h-full\", className)}>\n <nav className=\"flex flex-1 h-full items-center\">\n {([\"light\", \"dark\"] as Theme[]).map((theme) => (\n <Logo\n key={theme}\n href={logoHref}\n theme={theme}\n badge={logoBadge}\n additionalLinkAttrs={{\n className: cn(\"h-full focus-base rounded mr-4 lg:mr-8\", {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n }),\n }}\n />\n ))}\n <div className={FLEXIBLE_DESKTOP_CLASSES}>{nav}</div>\n </nav>\n <div className=\"flex md:hidden flex-1 items-center justify-end gap-6 h-full\">\n {searchButtonVisibility !== \"desktop\" ? wrappedSearchButton : null}\n <button\n className=\"cursor-pointer focus-base rounded flex items-center p-0\"\n onClick={() => setShowMenu(!showMenu)}\n aria-expanded={showMenu}\n aria-controls=\"mobile-menu\"\n aria-label=\"Toggle menu\"\n >\n <Icon\n name={\n showMenu\n ? \"icon-gui-x-mark-outline\"\n : \"icon-gui-bars-3-outline\"\n }\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n size=\"1.5rem\"\n />\n </button>\n </div>\n {searchBar ? (\n <div\n className={cn(\n FLEXIBLE_DESKTOP_CLASSES,\n \"justify-center\",\n headerCenterClassName,\n )}\n >\n {searchBar}\n </div>\n ) : null}\n <HeaderLinks\n className={cn(FLEXIBLE_DESKTOP_CLASSES, headerLinksClassName)}\n headerLinks={headerLinks}\n sessionState={sessionState}\n searchButton={wrappedSearchButton}\n searchButtonVisibility={searchButtonVisibility}\n />\n </div>\n </header>\n {showMenu ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40\",\n {\n \"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]\":\n !fadingOut,\n \"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]\":\n fadingOut,\n },\n )}\n onClick={closeMenu}\n onKeyDown={(e) => e.key === \"Escape\" && closeMenu()}\n role=\"presentation\"\n />\n <div\n id=\"mobile-menu\"\n className=\"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50\"\n style={{\n maxWidth: MAX_MOBILE_MENU_WIDTH,\n maxHeight: componentMaxHeight(\n HEADER_HEIGHT,\n HEADER_BOTTOM_MARGIN,\n ),\n }}\n ref={menuRef}\n role=\"navigation\"\n >\n {mobileNav}\n <HeaderLinks\n headerLinks={headerLinks}\n sessionState={sessionState}\n />\n </div>\n </>\n ) : null}\n </>\n );\n};\n\nexport default Header;\n"],"names":["React","useState","useEffect","useRef","useMemo","useCallback","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","COLLAPSE_TRIGGER_DISTANCE","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","className","isNoticeBannerEnabled","noticeHeight","searchBar","searchButton","logoHref","headerLinks","headerLinksClassName","headerCenterClassName","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","location","logoBadge","showMenu","setShowMenu","fadingOut","setFadingOut","noticeBannerVisible","setNoticeBannerVisible","menuRef","scrollpointClasses","setScrollpointClasses","length","headerStyle","height","top","headerClassName","closeMenu","setTimeout","handleNoticeClose","document","addEventListener","removeEventListener","handleScroll","noticeElement","querySelector","isNoticeClosedToBeHidden","classList","contains","window","scrollY","scrollpoint","element","getElementById","id","rect","getBoundingClientRect","bottom","throttledHandleScroll","handleResize","innerWidth","body","add","remove","wrappedSearchButton","div","header","role","style","map","theme","key","href","badge","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxWidth","maxHeight","ref"],"mappings":"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"}
|
package/core/Meganav.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useEffect,useMemo}from"react";import Header from"./Header";import Flyout from"./Flyout";import{menuItemsForHeader}from"./Meganav/data";import{MeganavMobile}from"./Meganav/MeganavMobile";import Notice from"./Notice";import{HEADER_HEIGHT}from"./utils/heights";const Meganav=({sessionState,notice,theme,themedScrollpoints,onNoticeClose})=>{const[noticeHeight,setNoticeHeight]=React.useState(0);const finalNoticeHeight=notice?noticeHeight:0;const mobileNavItems=useMemo(()=>menuItemsForHeader.filter(item=>!item.isHiddenMobile).map(({name,link,content})=>({name,link,content})),[]);const defaultThemedScrollpoints=[{id:"meganav",className:"ui-theme-light !bg-transparent !border-none"},{id:"meganav-theme-dark",className:"ui-theme-dark !bg-transparent !border-none"},{id:"main",className:"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b"},{id:"main-theme-dark",className:"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b"}];useEffect(()=>{if(!notice){setNoticeHeight(0)
|
|
1
|
+
import React,{useEffect,useMemo}from"react";import Header from"./Header";import Flyout from"./Flyout";import{menuItemsForHeader}from"./Meganav/data";import{MeganavMobile}from"./Meganav/MeganavMobile";import Notice from"./Notice";import{HEADER_HEIGHT}from"./utils/heights";const Meganav=({sessionState,notice,theme,themedScrollpoints,onNoticeClose})=>{const[noticeHeight,setNoticeHeight]=React.useState(0);const finalNoticeHeight=notice?noticeHeight:0;const mobileNavItems=useMemo(()=>menuItemsForHeader.filter(item=>!item.isHiddenMobile).map(({name,link,content})=>({name,link,content})),[]);const defaultThemedScrollpoints=[{id:"meganav",className:"ui-theme-light !bg-transparent !border-none"},{id:"meganav-theme-dark",className:"ui-theme-dark !bg-transparent !border-none"},{id:"main",className:"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b"},{id:"main-theme-dark",className:"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b"}];useEffect(()=>{if(!notice){if(noticeHeight!==0){setNoticeHeight(0)}return}const noticeElement=document.querySelector('[data-id="ui-notice"]');if(!noticeElement)return;const updateNoticeHeight=()=>{setNoticeHeight(noticeElement.getBoundingClientRect().height)};const observer=new ResizeObserver(updateNoticeHeight);observer.observe(noticeElement);const timeoutId=setTimeout(updateNoticeHeight,0);window.addEventListener("resize",updateNoticeHeight);return()=>{clearTimeout(timeoutId);observer.disconnect();window.removeEventListener("resize",updateNoticeHeight)}},[notice]);return React.createElement(React.Fragment,null,React.createElement("div",{className:"absolute inset-0 w-full z-50",id:theme==="dark"?"meganav-theme-dark":"meganav","data-testid":"meganav",style:{height:HEADER_HEIGHT+finalNoticeHeight}},notice&&React.createElement(Notice,{...notice.props,config:notice.config,onClose:onNoticeClose}),React.createElement(Header,{className:"max-w-screen-xl mx-auto px-0 sm:px-8 md:px-10 lg:px-16",isNoticeBannerEnabled:!!notice,noticeHeight:finalNoticeHeight,nav:React.createElement(Flyout,{menuItems:menuItemsForHeader,className:"justify-left z-40",flyOutClassName:"flex justify-left",viewPortClassName:"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300"}),mobileNav:React.createElement(MeganavMobile,{navItems:mobileNavItems}),headerLinks:[{href:"/contact",label:"Contact us"}],headerLinksClassName:"md:gap-x-6 ",sessionState:sessionState,themedScrollpoints:themedScrollpoints??defaultThemedScrollpoints})))};export default Meganav;
|
|
2
2
|
//# sourceMappingURL=Meganav.js.map
|
package/core/Meganav.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Meganav.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport Header, { HeaderSessionState, ThemedScrollpoint } from \"./Header\";\nimport Flyout from \"./Flyout\";\nimport { menuItemsForHeader } from \"./Meganav/data\";\nimport { MeganavMobile } from \"./Meganav/MeganavMobile\";\nimport Notice from \"./Notice\";\nimport { HEADER_HEIGHT } from \"./utils/heights\";\n\nexport type MeganavNoticeBannerProps = {\n props: {\n title: string;\n bodyText: string;\n buttonLink: string;\n buttonLabel: string;\n closeBtn: boolean;\n };\n config: {\n cookieId: string;\n noticeId: string | number;\n options: {\n collapse: boolean;\n };\n };\n};\n\nexport type MeganavProps = {\n sessionState: HeaderSessionState;\n notice?: MeganavNoticeBannerProps;\n theme?: string;\n themedScrollpoints?: ThemedScrollpoint[];\n onNoticeClose?: () => void;\n};\n\nconst Meganav = ({\n sessionState,\n notice,\n theme,\n themedScrollpoints,\n onNoticeClose,\n}: MeganavProps) => {\n const [noticeHeight, setNoticeHeight] = React.useState(0);\n\n const finalNoticeHeight = notice ? noticeHeight : 0;\n\n const mobileNavItems = useMemo(\n () =>\n menuItemsForHeader\n .filter((item) => !item.isHiddenMobile)\n .map(({ name, link, content }) => ({ name, link, content })),\n [],\n );\n\n const defaultThemedScrollpoints = [\n {\n id: \"meganav\",\n className: \"ui-theme-light !bg-transparent !border-none\",\n },\n {\n id: \"meganav-theme-dark\",\n className: \"ui-theme-dark !bg-transparent !border-none\",\n },\n {\n id: \"main\",\n className: \"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n {\n id: \"main-theme-dark\",\n className: \"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n ];\n\n useEffect(() => {\n if (!notice) {\n setNoticeHeight(0);\n return;\n }\n\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n if (!noticeElement) return;\n\n const updateNoticeHeight = () => {\n setNoticeHeight(noticeElement.getBoundingClientRect().height);\n };\n\n const observer = new ResizeObserver(updateNoticeHeight);\n observer.observe(noticeElement);\n\n const timeoutId = setTimeout(updateNoticeHeight, 0);\n window.addEventListener(\"resize\", updateNoticeHeight);\n\n return () => {\n clearTimeout(timeoutId);\n observer.disconnect();\n window.removeEventListener(\"resize\", updateNoticeHeight);\n };\n }, [notice]);\n\n return (\n <>\n <div\n className=\"absolute inset-0 w-full z-50\"\n id={theme === \"dark\" ? \"meganav-theme-dark\" : \"meganav\"}\n data-testid=\"meganav\"\n style={{ height: HEADER_HEIGHT + finalNoticeHeight }}\n >\n {notice && (\n <Notice\n {...notice.props}\n config={notice.config}\n onClose={onNoticeClose}\n />\n )}\n <Header\n className=\"max-w-screen-xl mx-auto px-0 sm:px-8 md:px-10 lg:px-16\"\n isNoticeBannerEnabled={!!notice}\n noticeHeight={finalNoticeHeight}\n nav={\n <Flyout\n menuItems={menuItemsForHeader}\n className=\"justify-left z-40\"\n flyOutClassName=\"flex justify-left\"\n viewPortClassName=\"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300\"\n />\n }\n mobileNav={<MeganavMobile navItems={mobileNavItems} />}\n headerLinks={[{ href: \"/contact\", label: \"Contact us\" }]}\n headerLinksClassName=\"md:gap-x-6 \"\n sessionState={sessionState}\n themedScrollpoints={themedScrollpoints ?? defaultThemedScrollpoints}\n />\n </div>\n </>\n );\n};\n\nexport default Meganav;\n"],"names":["React","useEffect","useMemo","Header","Flyout","menuItemsForHeader","MeganavMobile","Notice","HEADER_HEIGHT","Meganav","sessionState","notice","theme","themedScrollpoints","onNoticeClose","noticeHeight","setNoticeHeight","useState","finalNoticeHeight","mobileNavItems","filter","item","isHiddenMobile","map","name","link","content","defaultThemedScrollpoints","id","className","noticeElement","document","querySelector","updateNoticeHeight","getBoundingClientRect","height","observer","ResizeObserver","observe","timeoutId","setTimeout","window","addEventListener","clearTimeout","disconnect","removeEventListener","div","data-testid","style","props","config","onClose","isNoticeBannerEnabled","nav","menuItems","flyOutClassName","viewPortClassName","mobileNav","navItems","headerLinks","href","label","headerLinksClassName"],"mappings":"AAAA,OAAOA,OAASC,SAAS,CAAEC,OAAO,KAAQ,OAAQ,AAClD,QAAOC,WAAuD,UAAW,AACzE,QAAOC,WAAY,UAAW,AAC9B,QAASC,kBAAkB,KAAQ,gBAAiB,AACpD,QAASC,aAAa,KAAQ,yBAA0B,AACxD,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,iBAAkB,CA2BhD,MAAMC,QAAU,CAAC,CACfC,YAAY,CACZC,MAAM,CACNC,KAAK,CACLC,kBAAkB,CAClBC,aAAa,CACA,IACb,KAAM,CAACC,aAAcC,gBAAgB,CAAGhB,MAAMiB,QAAQ,CAAC,GAEvD,MAAMC,kBAAoBP,OAASI,aAAe,EAElD,MAAMI,eAAiBjB,QACrB,IACEG,mBACGe,MAAM,CAAC,AAACC,MAAS,CAACA,KAAKC,cAAc,EACrCC,GAAG,CAAC,CAAC,CAAEC,IAAI,CAAEC,IAAI,CAAEC,OAAO,CAAE,GAAM,CAAA,CAAEF,KAAMC,KAAMC,OAAQ,CAAA,GAC7D,EAAE,EAGJ,MAAMC,0BAA4B,CAChC,CACEC,GAAI,UACJC,UAAW,6CACb,EACA,CACED,GAAI,qBACJC,UAAW,4CACb,EACA,CACED,GAAI,OACJC,UAAW,6DACb,EACA,CACED,GAAI,kBACJC,UAAW,4DACb,EACD,CAED5B,UAAU,KACR,GAAI,CAACU,OAAQ,
|
|
1
|
+
{"version":3,"sources":["../../src/core/Meganav.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport Header, { HeaderSessionState, ThemedScrollpoint } from \"./Header\";\nimport Flyout from \"./Flyout\";\nimport { menuItemsForHeader } from \"./Meganav/data\";\nimport { MeganavMobile } from \"./Meganav/MeganavMobile\";\nimport Notice from \"./Notice\";\nimport { HEADER_HEIGHT } from \"./utils/heights\";\n\nexport type MeganavNoticeBannerProps = {\n props: {\n title: string;\n bodyText: string;\n buttonLink: string;\n buttonLabel: string;\n closeBtn: boolean;\n };\n config: {\n cookieId: string;\n noticeId: string | number;\n options: {\n collapse: boolean;\n };\n };\n};\n\nexport type MeganavProps = {\n sessionState: HeaderSessionState;\n notice?: MeganavNoticeBannerProps;\n theme?: string;\n themedScrollpoints?: ThemedScrollpoint[];\n onNoticeClose?: () => void;\n};\n\nconst Meganav = ({\n sessionState,\n notice,\n theme,\n themedScrollpoints,\n onNoticeClose,\n}: MeganavProps) => {\n const [noticeHeight, setNoticeHeight] = React.useState(0);\n\n const finalNoticeHeight = notice ? noticeHeight : 0;\n\n const mobileNavItems = useMemo(\n () =>\n menuItemsForHeader\n .filter((item) => !item.isHiddenMobile)\n .map(({ name, link, content }) => ({ name, link, content })),\n [],\n );\n\n const defaultThemedScrollpoints = [\n {\n id: \"meganav\",\n className: \"ui-theme-light !bg-transparent !border-none\",\n },\n {\n id: \"meganav-theme-dark\",\n className: \"ui-theme-dark !bg-transparent !border-none\",\n },\n {\n id: \"main\",\n className: \"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n {\n id: \"main-theme-dark\",\n className: \"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n ];\n\n useEffect(() => {\n if (!notice) {\n if (noticeHeight !== 0) {\n setNoticeHeight(0);\n }\n return;\n }\n\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n if (!noticeElement) return;\n\n const updateNoticeHeight = () => {\n setNoticeHeight(noticeElement.getBoundingClientRect().height);\n };\n\n const observer = new ResizeObserver(updateNoticeHeight);\n observer.observe(noticeElement);\n\n const timeoutId = setTimeout(updateNoticeHeight, 0);\n window.addEventListener(\"resize\", updateNoticeHeight);\n\n return () => {\n clearTimeout(timeoutId);\n observer.disconnect();\n window.removeEventListener(\"resize\", updateNoticeHeight);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [notice]);\n\n return (\n <>\n <div\n className=\"absolute inset-0 w-full z-50\"\n id={theme === \"dark\" ? \"meganav-theme-dark\" : \"meganav\"}\n data-testid=\"meganav\"\n style={{ height: HEADER_HEIGHT + finalNoticeHeight }}\n >\n {notice && (\n <Notice\n {...notice.props}\n config={notice.config}\n onClose={onNoticeClose}\n />\n )}\n <Header\n className=\"max-w-screen-xl mx-auto px-0 sm:px-8 md:px-10 lg:px-16\"\n isNoticeBannerEnabled={!!notice}\n noticeHeight={finalNoticeHeight}\n nav={\n <Flyout\n menuItems={menuItemsForHeader}\n className=\"justify-left z-40\"\n flyOutClassName=\"flex justify-left\"\n viewPortClassName=\"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300\"\n />\n }\n mobileNav={<MeganavMobile navItems={mobileNavItems} />}\n headerLinks={[{ href: \"/contact\", label: \"Contact us\" }]}\n headerLinksClassName=\"md:gap-x-6 \"\n sessionState={sessionState}\n themedScrollpoints={themedScrollpoints ?? defaultThemedScrollpoints}\n />\n </div>\n </>\n );\n};\n\nexport default Meganav;\n"],"names":["React","useEffect","useMemo","Header","Flyout","menuItemsForHeader","MeganavMobile","Notice","HEADER_HEIGHT","Meganav","sessionState","notice","theme","themedScrollpoints","onNoticeClose","noticeHeight","setNoticeHeight","useState","finalNoticeHeight","mobileNavItems","filter","item","isHiddenMobile","map","name","link","content","defaultThemedScrollpoints","id","className","noticeElement","document","querySelector","updateNoticeHeight","getBoundingClientRect","height","observer","ResizeObserver","observe","timeoutId","setTimeout","window","addEventListener","clearTimeout","disconnect","removeEventListener","div","data-testid","style","props","config","onClose","isNoticeBannerEnabled","nav","menuItems","flyOutClassName","viewPortClassName","mobileNav","navItems","headerLinks","href","label","headerLinksClassName"],"mappings":"AAAA,OAAOA,OAASC,SAAS,CAAEC,OAAO,KAAQ,OAAQ,AAClD,QAAOC,WAAuD,UAAW,AACzE,QAAOC,WAAY,UAAW,AAC9B,QAASC,kBAAkB,KAAQ,gBAAiB,AACpD,QAASC,aAAa,KAAQ,yBAA0B,AACxD,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,iBAAkB,CA2BhD,MAAMC,QAAU,CAAC,CACfC,YAAY,CACZC,MAAM,CACNC,KAAK,CACLC,kBAAkB,CAClBC,aAAa,CACA,IACb,KAAM,CAACC,aAAcC,gBAAgB,CAAGhB,MAAMiB,QAAQ,CAAC,GAEvD,MAAMC,kBAAoBP,OAASI,aAAe,EAElD,MAAMI,eAAiBjB,QACrB,IACEG,mBACGe,MAAM,CAAC,AAACC,MAAS,CAACA,KAAKC,cAAc,EACrCC,GAAG,CAAC,CAAC,CAAEC,IAAI,CAAEC,IAAI,CAAEC,OAAO,CAAE,GAAM,CAAA,CAAEF,KAAMC,KAAMC,OAAQ,CAAA,GAC7D,EAAE,EAGJ,MAAMC,0BAA4B,CAChC,CACEC,GAAI,UACJC,UAAW,6CACb,EACA,CACED,GAAI,qBACJC,UAAW,4CACb,EACA,CACED,GAAI,OACJC,UAAW,6DACb,EACA,CACED,GAAI,kBACJC,UAAW,4DACb,EACD,CAED5B,UAAU,KACR,GAAI,CAACU,OAAQ,CACX,GAAII,eAAiB,EAAG,CACtBC,gBAAgB,EAClB,CACA,MACF,CAEA,MAAMc,cAAgBC,SAASC,aAAa,CAAC,yBAC7C,GAAI,CAACF,cAAe,OAEpB,MAAMG,mBAAqB,KACzBjB,gBAAgBc,cAAcI,qBAAqB,GAAGC,MAAM,CAC9D,EAEA,MAAMC,SAAW,IAAIC,eAAeJ,oBACpCG,SAASE,OAAO,CAACR,eAEjB,MAAMS,UAAYC,WAAWP,mBAAoB,GACjDQ,OAAOC,gBAAgB,CAAC,SAAUT,oBAElC,MAAO,KACLU,aAAaJ,WACbH,SAASQ,UAAU,GACnBH,OAAOI,mBAAmB,CAAC,SAAUZ,mBACvC,CAEF,EAAG,CAACtB,OAAO,EAEX,OACE,wCACE,oBAACmC,OACCjB,UAAU,+BACVD,GAAIhB,QAAU,OAAS,qBAAuB,UAC9CmC,cAAY,UACZC,MAAO,CAAEb,OAAQ3B,cAAgBU,iBAAkB,GAElDP,QACC,oBAACJ,QACE,GAAGI,OAAOsC,KAAK,CAChBC,OAAQvC,OAAOuC,MAAM,CACrBC,QAASrC,gBAGb,oBAACX,QACC0B,UAAU,yDACVuB,sBAAuB,CAAC,CAACzC,OACzBI,aAAcG,kBACdmC,IACE,oBAACjD,QACCkD,UAAWjD,mBACXwB,UAAU,oBACV0B,gBAAgB,oBAChBC,kBAAkB,iIAGtBC,UAAW,oBAACnD,eAAcoD,SAAUvC,iBACpCwC,YAAa,CAAC,CAAEC,KAAM,WAAYC,MAAO,YAAa,EAAE,CACxDC,qBAAqB,cACrBpD,aAAcA,aACdG,mBAAoBA,oBAAsBc,6BAKpD,CAEA,gBAAelB,OAAQ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{Fragment,useEffect,useRef,useState}from"react";import{throttle}from"es-toolkit/compat";import Icon from"../Icon";import LinkButton from"../LinkButton";import Tooltip from"../Tooltip";import cn from"../utils/cn";const PricingCards=({data,delimiter})=>{const descriptionsRef=useRef([]);const[descriptionHeight,setDescriptionHeight]=useState(0);const determineMaxDescriptionHeight=throttle(()=>{if(descriptionsRef.current.length){setDescriptionHeight(Math.max(...descriptionsRef.current.map(description=>description?.getBoundingClientRect().height??0)))}},100);
|
|
1
|
+
import React,{Fragment,useEffect,useRef,useState}from"react";import{throttle}from"es-toolkit/compat";import Icon from"../Icon";import LinkButton from"../LinkButton";import Tooltip from"../Tooltip";import cn from"../utils/cn";const PricingCards=({data,delimiter})=>{const descriptionsRef=useRef([]);const[descriptionHeight,setDescriptionHeight]=useState(0);useEffect(()=>{const determineMaxDescriptionHeight=throttle(()=>{if(descriptionsRef.current.length){setDescriptionHeight(Math.max(...descriptionsRef.current.map(description=>description?.getBoundingClientRect().height??0)))}},100);determineMaxDescriptionHeight();window.addEventListener("resize",determineMaxDescriptionHeight);return()=>{window.removeEventListener("resize",determineMaxDescriptionHeight);determineMaxDescriptionHeight.cancel()}},[]);const delimiterColumn=index=>delimiter&&index%2===1?React.createElement("div",{className:cn("flex items-center justify-center w-full @[920px]:w-5",{"m-2":delimiter!=="blank"})},delimiter!=="blank"?React.createElement(Icon,{name:delimiter,size:"20px",additionalCSS:"text-neutral-800 dark:text-neutral-500"}):null):null;const gridRules={nonDelimited:"grid @[552px]:grid-cols-2 @[1104px]:grid-cols-4",delimited:"flex flex-col items-center @[920px]:flex-row"};const borderClasses=color=>{const classes={neutral:{border:"border-neutral-600 dark:border-neutral-700",bg:"bg-neutral-600 dark:bg-neutral-700"},blue:{border:"border-blue-400 dark:border-blue-600",bg:"bg-blue-400 dark:bg-blue-600"},orange:{border:"border-orange-600 dark:border-orange-600",bg:"bg-orange-600 dark:bg-orange-600"}};if(color&&classes[color]){return classes[color]}};return React.createElement("div",{className:"@container flex justify-center","data-testid":delimiter?"delimited-pricing-card-group":"pricing-card-group"},React.createElement("div",{className:cn("gap-2",delimiter?gridRules.delimited:gridRules.nonDelimited)},data.map(({title,description,price,cta,sections,border,bottomCta},index)=>React.createElement(Fragment,{key:title.content},delimiterColumn(index),React.createElement("div",{className:cn("relative border flex-1 px-6 pt-6 pb-4 flex flex-col gap-6 rounded-2xl group min-w-[17rem] backdrop-blur bg-neutral-100 dark:bg-neutral-1200",borderClasses(border?.color)?.border??"border-neutral-200 dark:border-neutral-1100",border?.style,{"@[520px]:flex-row @[920px]:flex-col":delimiter}),"data-testid":delimiter?"delimited-pricing-card":"pricing-card"},border?React.createElement("div",{className:cn("flex items-center absolute z-10 -top-3 self-center font-semibold uppercase text-neutral-000 font-sans h-6 text-[11px] px-2.5 py-0.5 rounded-2xl select-none tracking-widest",borderClasses(border?.color)?.border,borderClasses(border?.color)?.bg)},border.text):null,React.createElement("div",{className:cn(`relative z-10 flex flex-col gap-4`,{"@[520px]:flex-1 @[920px]:flex-none":delimiter})},React.createElement("div",null,React.createElement("div",{className:"flex items-center mb-1"},React.createElement("p",{className:cn(title.className,title.color)},title.content),title.tooltip?React.createElement(Tooltip,{interactive:typeof title.tooltip!=="string",iconSize:"1.25rem"},title.tooltip):null),React.createElement("p",{className:cn("ui-text-h1 text-h1-xl h-5 block",description.className,description.color),style:{height:descriptionHeight}},React.createElement("span",{ref:el=>descriptionsRef.current[index]=el},description.content))),React.createElement("div",{className:cn("flex items-end gap-2",{"@[520px]:flex-col @[520px]:items-start @[920px]:flex-row @[920px]:items-end":delimiter})},React.createElement("p",{className:"ui-text-h1 text-h1-xl font-medium tracking-tight leading-none text-neutral-1300 dark:text-neutral-000"},price.amount),React.createElement("div",{className:"ui-text-p3 text-neutral-1300 dark:text-neutral-000"},price.content)),cta?React.createElement("div",{className:"group"},React.createElement(LinkButton,{className:cn("w-full",cta.className),variant:cta.isPriority?"priority":"primary",href:cta.url,onClick:cta.onClick,disabled:cta.disabled,rightIcon:"icon-gui-arrow-right-outline",iconColor:cta.iconColor},cta.text)):delimiter?null:React.createElement("div",{className:"flex items-center justify-center h-12 w-full"},React.createElement("hr",{className:"border-neutral-500 dark:border-neutral-800 w-16"}))),React.createElement("div",{className:"flex flex-col gap-4 relative z-10 flex-grow"},sections.map(({title,items,listItemColors})=>React.createElement("div",{key:title,className:"flex flex-col gap-3"},React.createElement("p",{className:"text-neutral-700 dark:text-neutral-600 font-mono uppercase text-overline2 font-medium tracking-[0.12em] h-4"},title),React.createElement("div",{className:cn({"flex flex-col":!delimiter})},items.map((item,index)=>Array.isArray(item)?React.createElement("div",{key:item[0],className:cn("flex justify-between gap-4 px-2 -mx-2",index===0?"py-2":"py-1",index>0&&index%2===0?"bg-blue-100 dark:bg-blue-900 rounded-md":"")},item.map((subItem,subIndex)=>React.createElement("span",{key:subItem,className:cn("ui-text-p3",index===0?"font-bold":"font-medium","text-neutral-1000 dark:text-neutral-300 leading-[1.4rem]",subIndex%2===1?"text-right":"")},subItem))):React.createElement("div",{key:item,className:"flex items-start gap-2"},listItemColors?React.createElement(Icon,{name:"icon-gui-check-circled-fill",color:listItemColors.background,secondaryColor:listItemColors.foreground,size:"16px",additionalCSS:"mt-1"}):null,React.createElement("div",{className:cn(`flex-1 font-medium text-neutral-1000 dark:text-neutral-300 ui-text-p3`)},item))))))),bottomCta&&React.createElement("div",null,React.createElement("div",{className:"border-t border-neutral-200 dark:border-neutral-1100 -mx-6"}),React.createElement("a",{href:bottomCta.url,className:cn("text-[13px] font-sans font-semibold group/bottom-cta cursor-pointer pt-4 flex items-center","text-neutral-700 dark:text-neutral-600 hover:text-neutral-1300 dark:hover:text-neutral-000 focus:outline-none focus-visible:outline-gui-focus")},bottomCta.text,React.createElement(Icon,{name:"icon-gui-arrow-down-outline",size:"12px",color:bottomCta.iconColor,additionalCSS:cn("align-middle ml-2 relative transition-[bottom] bottom-0 group-hover/bottom-cta:-bottom-0.5")})))),delimiterColumn(index)))))};export default PricingCards;
|
|
2
2
|
//# sourceMappingURL=PricingCards.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/Pricing/PricingCards.tsx"],"sourcesContent":["import React, { Fragment, useEffect, useRef, useState } from \"react\";\nimport { throttle } from \"es-toolkit/compat\";\nimport type { PricingDataFeature } from \"./types\";\nimport Icon from \"../Icon\";\nimport LinkButton from \"../LinkButton\";\nimport { IconName } from \"../Icon/types\";\nimport Tooltip from \"../Tooltip\";\nimport cn from \"../utils/cn\";\n\nexport type PricingCardsProps = {\n data: PricingDataFeature[];\n delimiter?: IconName | \"blank\";\n};\n\nconst PricingCards = ({ data, delimiter }: PricingCardsProps) => {\n const descriptionsRef = useRef<(HTMLSpanElement | null)[]>([]);\n const [descriptionHeight, setDescriptionHeight] = useState<number>(0);\n\n const determineMaxDescriptionHeight = throttle(() => {\n if (descriptionsRef.current.length) {\n setDescriptionHeight(\n Math.max(\n ...descriptionsRef.current.map(\n (description) => description?.getBoundingClientRect().height ?? 0,\n ),\n ),\n );\n }\n }, 100);\n\n useEffect(() => {\n determineMaxDescriptionHeight();\n\n window.addEventListener(\"resize\", determineMaxDescriptionHeight);\n\n return () => {\n window.removeEventListener(\"resize\", determineMaxDescriptionHeight);\n determineMaxDescriptionHeight.cancel();\n };\n }, [determineMaxDescriptionHeight]);\n\n const delimiterColumn = (index: number) =>\n delimiter && index % 2 === 1 ? (\n <div\n className={cn(\"flex items-center justify-center w-full @[920px]:w-5\", {\n \"m-2\": delimiter !== \"blank\",\n })}\n >\n {delimiter !== \"blank\" ? (\n <Icon\n name={delimiter}\n size=\"20px\"\n additionalCSS={\"text-neutral-800 dark:text-neutral-500\"}\n />\n ) : null}\n </div>\n ) : null;\n\n const gridRules = {\n nonDelimited: \"grid @[552px]:grid-cols-2 @[1104px]:grid-cols-4\",\n delimited: \"flex flex-col items-center @[920px]:flex-row\",\n };\n\n const borderClasses = (color?: \"neutral\" | \"blue\" | \"orange\") => {\n const classes: Record<\n string,\n {\n border: string;\n bg: string;\n }\n > = {\n neutral: {\n border: \"border-neutral-600 dark:border-neutral-700\",\n bg: \"bg-neutral-600 dark:bg-neutral-700\",\n },\n blue: {\n border: \"border-blue-400 dark:border-blue-600\",\n bg: \"bg-blue-400 dark:bg-blue-600\",\n },\n orange: {\n border: \"border-orange-600 dark:border-orange-600\",\n bg: \"bg-orange-600 dark:bg-orange-600\",\n },\n };\n\n if (color && classes[color]) {\n return classes[color];\n }\n };\n\n return (\n <div\n className=\"@container flex justify-center\"\n data-testid={\n delimiter ? \"delimited-pricing-card-group\" : \"pricing-card-group\"\n }\n >\n <div\n className={cn(\n \"gap-2\",\n delimiter ? gridRules.delimited : gridRules.nonDelimited,\n )}\n >\n {data.map(\n (\n { title, description, price, cta, sections, border, bottomCta },\n index,\n ) => (\n <Fragment key={title.content}>\n {delimiterColumn(index)}\n <div\n className={cn(\n \"relative border flex-1 px-6 pt-6 pb-4 flex flex-col gap-6 rounded-2xl group min-w-[17rem] backdrop-blur bg-neutral-100 dark:bg-neutral-1200\",\n borderClasses(border?.color)?.border ??\n \"border-neutral-200 dark:border-neutral-1100\",\n border?.style,\n { \"@[520px]:flex-row @[920px]:flex-col\": delimiter },\n )}\n data-testid={\n delimiter ? \"delimited-pricing-card\" : \"pricing-card\"\n }\n >\n {border ? (\n <div\n className={cn(\n \"flex items-center absolute z-10 -top-3 self-center font-semibold uppercase text-neutral-000 font-sans h-6 text-[11px] px-2.5 py-0.5 rounded-2xl select-none tracking-widest\",\n borderClasses(border?.color)?.border,\n borderClasses(border?.color)?.bg,\n )}\n >\n {border.text}\n </div>\n ) : null}\n <div\n className={cn(`relative z-10 flex flex-col gap-4`, {\n \"@[520px]:flex-1 @[920px]:flex-none\": delimiter,\n })}\n >\n <div>\n <div className=\"flex items-center mb-1\">\n <p className={cn(title.className, title.color)}>\n {title.content}\n </p>\n {title.tooltip ? (\n <Tooltip\n interactive={typeof title.tooltip !== \"string\"}\n iconSize=\"1.25rem\"\n >\n {title.tooltip}\n </Tooltip>\n ) : null}\n </div>\n <p\n className={cn(\n \"ui-text-h1 text-h1-xl h-5 block\",\n description.className,\n description.color,\n )}\n style={{ height: descriptionHeight }}\n >\n <span ref={(el) => (descriptionsRef.current[index] = el)}>\n {description.content}\n </span>\n </p>\n </div>\n <div\n className={cn(\"flex items-end gap-2\", {\n \"@[520px]:flex-col @[520px]:items-start @[920px]:flex-row @[920px]:items-end\":\n delimiter,\n })}\n >\n <p className=\"ui-text-h1 text-h1-xl font-medium tracking-tight leading-none text-neutral-1300 dark:text-neutral-000\">\n {price.amount}\n </p>\n <div className=\"ui-text-p3 text-neutral-1300 dark:text-neutral-000\">\n {price.content}\n </div>\n </div>\n {cta ? (\n <div className=\"group\">\n <LinkButton\n className={cn(\"w-full\", cta.className)}\n variant={cta.isPriority ? \"priority\" : \"primary\"}\n href={cta.url}\n onClick={cta.onClick}\n disabled={cta.disabled}\n rightIcon=\"icon-gui-arrow-right-outline\"\n iconColor={cta.iconColor}\n >\n {cta.text}\n </LinkButton>\n </div>\n ) : delimiter ? null : (\n <div className=\"flex items-center justify-center h-12 w-full\">\n <hr className=\"border-neutral-500 dark:border-neutral-800 w-16\" />\n </div>\n )}\n </div>\n <div className=\"flex flex-col gap-4 relative z-10 flex-grow\">\n {sections.map(({ title, items, listItemColors }) => (\n <div key={title} className=\"flex flex-col gap-3\">\n <p className=\"text-neutral-700 dark:text-neutral-600 font-mono uppercase text-overline2 font-medium tracking-[0.12em] h-4\">\n {title}\n </p>\n <div className={cn({ \"flex flex-col\": !delimiter })}>\n {items.map((item, index) =>\n Array.isArray(item) ? (\n <div\n key={item[0]}\n className={cn(\n \"flex justify-between gap-4 px-2 -mx-2\",\n index === 0 ? \"py-2\" : \"py-1\",\n index > 0 && index % 2 === 0\n ? \"bg-blue-100 dark:bg-blue-900 rounded-md\"\n : \"\",\n )}\n >\n {item.map((subItem, subIndex) => (\n <span\n key={subItem}\n className={cn(\n \"ui-text-p3\",\n index === 0 ? \"font-bold\" : \"font-medium\",\n \"text-neutral-1000 dark:text-neutral-300 leading-[1.4rem]\",\n subIndex % 2 === 1 ? \"text-right\" : \"\",\n )}\n >\n {subItem}\n </span>\n ))}\n </div>\n ) : (\n <div key={item} className=\"flex items-start gap-2\">\n {listItemColors ? (\n <Icon\n name=\"icon-gui-check-circled-fill\"\n color={listItemColors.background}\n secondaryColor={listItemColors.foreground}\n size=\"16px\"\n additionalCSS=\"mt-1\"\n />\n ) : null}\n <div\n className={cn(\n `flex-1 font-medium text-neutral-1000 dark:text-neutral-300 ui-text-p3`,\n )}\n >\n {item}\n </div>\n </div>\n ),\n )}\n </div>\n </div>\n ))}\n </div>\n\n {bottomCta && (\n <div>\n <div className=\"border-t border-neutral-200 dark:border-neutral-1100 -mx-6\"></div>\n <a\n href={bottomCta.url}\n className={cn(\n \"text-[13px] font-sans font-semibold group/bottom-cta cursor-pointer pt-4 flex items-center\",\n \"text-neutral-700 dark:text-neutral-600 hover:text-neutral-1300 dark:hover:text-neutral-000 focus:outline-none focus-visible:outline-gui-focus\",\n )}\n >\n {bottomCta.text}\n <Icon\n name=\"icon-gui-arrow-down-outline\"\n size=\"12px\"\n color={bottomCta.iconColor}\n additionalCSS={cn(\n \"align-middle ml-2 relative transition-[bottom] bottom-0 group-hover/bottom-cta:-bottom-0.5\",\n )}\n />\n </a>\n </div>\n )}\n </div>\n {delimiterColumn(index)}\n </Fragment>\n ),\n )}\n </div>\n </div>\n );\n};\n\nexport default PricingCards;\n"],"names":["React","Fragment","useEffect","useRef","useState","throttle","Icon","LinkButton","Tooltip","cn","PricingCards","data","delimiter","descriptionsRef","descriptionHeight","setDescriptionHeight","determineMaxDescriptionHeight","current","length","Math","max","map","description","getBoundingClientRect","height","window","addEventListener","removeEventListener","cancel","delimiterColumn","index","div","className","name","size","additionalCSS","gridRules","nonDelimited","delimited","borderClasses","color","classes","neutral","border","bg","blue","orange","data-testid","title","price","cta","sections","bottomCta","key","content","style","text","p","tooltip","interactive","iconSize","span","ref","el","amount","variant","isPriority","href","url","onClick","disabled","rightIcon","iconColor","hr","items","listItemColors","item","Array","isArray","subItem","subIndex","background","secondaryColor","foreground","a"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/Pricing/PricingCards.tsx"],"sourcesContent":["import React, { Fragment, useEffect, useRef, useState } from \"react\";\nimport { throttle } from \"es-toolkit/compat\";\nimport type { PricingDataFeature } from \"./types\";\nimport Icon from \"../Icon\";\nimport LinkButton from \"../LinkButton\";\nimport { IconName } from \"../Icon/types\";\nimport Tooltip from \"../Tooltip\";\nimport cn from \"../utils/cn\";\n\nexport type PricingCardsProps = {\n data: PricingDataFeature[];\n delimiter?: IconName | \"blank\";\n};\n\nconst PricingCards = ({ data, delimiter }: PricingCardsProps) => {\n const descriptionsRef = useRef<(HTMLSpanElement | null)[]>([]);\n const [descriptionHeight, setDescriptionHeight] = useState<number>(0);\n\n useEffect(() => {\n const determineMaxDescriptionHeight = throttle(() => {\n if (descriptionsRef.current.length) {\n setDescriptionHeight(\n Math.max(\n ...descriptionsRef.current.map(\n (description) => description?.getBoundingClientRect().height ?? 0,\n ),\n ),\n );\n }\n }, 100);\n\n determineMaxDescriptionHeight();\n\n window.addEventListener(\"resize\", determineMaxDescriptionHeight);\n\n return () => {\n window.removeEventListener(\"resize\", determineMaxDescriptionHeight);\n determineMaxDescriptionHeight.cancel();\n };\n }, []);\n\n const delimiterColumn = (index: number) =>\n delimiter && index % 2 === 1 ? (\n <div\n className={cn(\"flex items-center justify-center w-full @[920px]:w-5\", {\n \"m-2\": delimiter !== \"blank\",\n })}\n >\n {delimiter !== \"blank\" ? (\n <Icon\n name={delimiter}\n size=\"20px\"\n additionalCSS={\"text-neutral-800 dark:text-neutral-500\"}\n />\n ) : null}\n </div>\n ) : null;\n\n const gridRules = {\n nonDelimited: \"grid @[552px]:grid-cols-2 @[1104px]:grid-cols-4\",\n delimited: \"flex flex-col items-center @[920px]:flex-row\",\n };\n\n const borderClasses = (color?: \"neutral\" | \"blue\" | \"orange\") => {\n const classes: Record<\n string,\n {\n border: string;\n bg: string;\n }\n > = {\n neutral: {\n border: \"border-neutral-600 dark:border-neutral-700\",\n bg: \"bg-neutral-600 dark:bg-neutral-700\",\n },\n blue: {\n border: \"border-blue-400 dark:border-blue-600\",\n bg: \"bg-blue-400 dark:bg-blue-600\",\n },\n orange: {\n border: \"border-orange-600 dark:border-orange-600\",\n bg: \"bg-orange-600 dark:bg-orange-600\",\n },\n };\n\n if (color && classes[color]) {\n return classes[color];\n }\n };\n\n return (\n <div\n className=\"@container flex justify-center\"\n data-testid={\n delimiter ? \"delimited-pricing-card-group\" : \"pricing-card-group\"\n }\n >\n <div\n className={cn(\n \"gap-2\",\n delimiter ? gridRules.delimited : gridRules.nonDelimited,\n )}\n >\n {data.map(\n (\n { title, description, price, cta, sections, border, bottomCta },\n index,\n ) => (\n <Fragment key={title.content}>\n {delimiterColumn(index)}\n <div\n className={cn(\n \"relative border flex-1 px-6 pt-6 pb-4 flex flex-col gap-6 rounded-2xl group min-w-[17rem] backdrop-blur bg-neutral-100 dark:bg-neutral-1200\",\n borderClasses(border?.color)?.border ??\n \"border-neutral-200 dark:border-neutral-1100\",\n border?.style,\n { \"@[520px]:flex-row @[920px]:flex-col\": delimiter },\n )}\n data-testid={\n delimiter ? \"delimited-pricing-card\" : \"pricing-card\"\n }\n >\n {border ? (\n <div\n className={cn(\n \"flex items-center absolute z-10 -top-3 self-center font-semibold uppercase text-neutral-000 font-sans h-6 text-[11px] px-2.5 py-0.5 rounded-2xl select-none tracking-widest\",\n borderClasses(border?.color)?.border,\n borderClasses(border?.color)?.bg,\n )}\n >\n {border.text}\n </div>\n ) : null}\n <div\n className={cn(`relative z-10 flex flex-col gap-4`, {\n \"@[520px]:flex-1 @[920px]:flex-none\": delimiter,\n })}\n >\n <div>\n <div className=\"flex items-center mb-1\">\n <p className={cn(title.className, title.color)}>\n {title.content}\n </p>\n {title.tooltip ? (\n <Tooltip\n interactive={typeof title.tooltip !== \"string\"}\n iconSize=\"1.25rem\"\n >\n {title.tooltip}\n </Tooltip>\n ) : null}\n </div>\n <p\n className={cn(\n \"ui-text-h1 text-h1-xl h-5 block\",\n description.className,\n description.color,\n )}\n style={{ height: descriptionHeight }}\n >\n <span ref={(el) => (descriptionsRef.current[index] = el)}>\n {description.content}\n </span>\n </p>\n </div>\n <div\n className={cn(\"flex items-end gap-2\", {\n \"@[520px]:flex-col @[520px]:items-start @[920px]:flex-row @[920px]:items-end\":\n delimiter,\n })}\n >\n <p className=\"ui-text-h1 text-h1-xl font-medium tracking-tight leading-none text-neutral-1300 dark:text-neutral-000\">\n {price.amount}\n </p>\n <div className=\"ui-text-p3 text-neutral-1300 dark:text-neutral-000\">\n {price.content}\n </div>\n </div>\n {cta ? (\n <div className=\"group\">\n <LinkButton\n className={cn(\"w-full\", cta.className)}\n variant={cta.isPriority ? \"priority\" : \"primary\"}\n href={cta.url}\n onClick={cta.onClick}\n disabled={cta.disabled}\n rightIcon=\"icon-gui-arrow-right-outline\"\n iconColor={cta.iconColor}\n >\n {cta.text}\n </LinkButton>\n </div>\n ) : delimiter ? null : (\n <div className=\"flex items-center justify-center h-12 w-full\">\n <hr className=\"border-neutral-500 dark:border-neutral-800 w-16\" />\n </div>\n )}\n </div>\n <div className=\"flex flex-col gap-4 relative z-10 flex-grow\">\n {sections.map(({ title, items, listItemColors }) => (\n <div key={title} className=\"flex flex-col gap-3\">\n <p className=\"text-neutral-700 dark:text-neutral-600 font-mono uppercase text-overline2 font-medium tracking-[0.12em] h-4\">\n {title}\n </p>\n <div className={cn({ \"flex flex-col\": !delimiter })}>\n {items.map((item, index) =>\n Array.isArray(item) ? (\n <div\n key={item[0]}\n className={cn(\n \"flex justify-between gap-4 px-2 -mx-2\",\n index === 0 ? \"py-2\" : \"py-1\",\n index > 0 && index % 2 === 0\n ? \"bg-blue-100 dark:bg-blue-900 rounded-md\"\n : \"\",\n )}\n >\n {item.map((subItem, subIndex) => (\n <span\n key={subItem}\n className={cn(\n \"ui-text-p3\",\n index === 0 ? \"font-bold\" : \"font-medium\",\n \"text-neutral-1000 dark:text-neutral-300 leading-[1.4rem]\",\n subIndex % 2 === 1 ? \"text-right\" : \"\",\n )}\n >\n {subItem}\n </span>\n ))}\n </div>\n ) : (\n <div key={item} className=\"flex items-start gap-2\">\n {listItemColors ? (\n <Icon\n name=\"icon-gui-check-circled-fill\"\n color={listItemColors.background}\n secondaryColor={listItemColors.foreground}\n size=\"16px\"\n additionalCSS=\"mt-1\"\n />\n ) : null}\n <div\n className={cn(\n `flex-1 font-medium text-neutral-1000 dark:text-neutral-300 ui-text-p3`,\n )}\n >\n {item}\n </div>\n </div>\n ),\n )}\n </div>\n </div>\n ))}\n </div>\n\n {bottomCta && (\n <div>\n <div className=\"border-t border-neutral-200 dark:border-neutral-1100 -mx-6\"></div>\n <a\n href={bottomCta.url}\n className={cn(\n \"text-[13px] font-sans font-semibold group/bottom-cta cursor-pointer pt-4 flex items-center\",\n \"text-neutral-700 dark:text-neutral-600 hover:text-neutral-1300 dark:hover:text-neutral-000 focus:outline-none focus-visible:outline-gui-focus\",\n )}\n >\n {bottomCta.text}\n <Icon\n name=\"icon-gui-arrow-down-outline\"\n size=\"12px\"\n color={bottomCta.iconColor}\n additionalCSS={cn(\n \"align-middle ml-2 relative transition-[bottom] bottom-0 group-hover/bottom-cta:-bottom-0.5\",\n )}\n />\n </a>\n </div>\n )}\n </div>\n {delimiterColumn(index)}\n </Fragment>\n ),\n )}\n </div>\n </div>\n );\n};\n\nexport default PricingCards;\n"],"names":["React","Fragment","useEffect","useRef","useState","throttle","Icon","LinkButton","Tooltip","cn","PricingCards","data","delimiter","descriptionsRef","descriptionHeight","setDescriptionHeight","determineMaxDescriptionHeight","current","length","Math","max","map","description","getBoundingClientRect","height","window","addEventListener","removeEventListener","cancel","delimiterColumn","index","div","className","name","size","additionalCSS","gridRules","nonDelimited","delimited","borderClasses","color","classes","neutral","border","bg","blue","orange","data-testid","title","price","cta","sections","bottomCta","key","content","style","text","p","tooltip","interactive","iconSize","span","ref","el","amount","variant","isPriority","href","url","onClick","disabled","rightIcon","iconColor","hr","items","listItemColors","item","Array","isArray","subItem","subIndex","background","secondaryColor","foreground","a"],"mappings":"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"}
|