@ably/ui 17.6.2-dev.90894fc5 → 17.6.3
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/CodeSnippet.js +1 -1
- package/core/CodeSnippet.js.map +1 -1
- package/core/Header.js +1 -1
- package/core/Header.js.map +1 -1
- package/core/Logo.js.map +1 -1
- package/index.d.ts +3 -3
- package/package.json +6 -6
package/core/CodeSnippet.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useState,useEffect,Children,isValidElement,useRef,useCallback,useMemo}from"react";import Code from"./Code";import cn from"./utils/cn";import Icon from"./Icon";import{getLanguageInfo,stripSdkType}from"./CodeSnippet/languages";import LanguageSelector from"./CodeSnippet/LanguageSelector";import ApiKeySelector from"./CodeSnippet/ApiKeySelector";import useCopyToClipboard from"./utils/useCopyToClipboard";import PlainCodeView from"./CodeSnippet/PlainCodeView";import CopyButton from"./CodeSnippet/CopyButton";import TooltipButton from"./CodeSnippet/TooltipButton";const substituteApiKey=(content,apiKey,mask=true)=>{return content.replace(/\{\{API_KEY\}\}/g,mask?`${apiKey.split(":")[0]}:*****`:apiKey)};const CodeSnippet=({fixed=false,headerRow=false,title="Code",children,className,lang,onChange,apiKeys,sdk,showCodeLines=true,languageOrdering})=>{const codeRef=useRef(null);const{isCopied,copy}=useCopyToClipboard();const[selectedApiKey,setSelectedApiKey]=useState(()=>apiKeys?.[0]?.keys?.[0]?.key??"");useEffect(()=>{if(!selectedApiKey&&apiKeys&&apiKeys.length>0){setSelectedApiKey(apiKeys[0].keys?.[0]?.key)}},[apiKeys,selectedApiKey]);useEffect(()=>{const element=codeRef.current;if(!element)return;const unmaskRenderedApiKey=(content,apiKey)=>{return content.replace(/(['"]?)([^:'"]+):\*{5}\1/g,`$1${apiKey}$1`)};const handleCopy=event=>{const selection=window.getSelection();if(!selection||selection.rangeCount===0)return;const selectedText=selection.toString();if(!selectedText)return;const range=selection.getRangeAt(0);if(!element.contains(range.commonAncestorContainer))return;const modifiedText=unmaskRenderedApiKey(selectedText,selectedApiKey);event.clipboardData?.setData("text/plain",modifiedText);event.preventDefault()};document.addEventListener("copy",handleCopy);return()=>{document.removeEventListener("copy",handleCopy)}},[codeRef.current,selectedApiKey]);const extractLanguageFromCode=useCallback(codeElement=>{if(!codeElement||!codeElement.props.className)return null;const classNames=codeElement.props.className.split(" ");const langClass=classNames.find(cls=>cls.startsWith("language-"));if(!langClass)return null;return langClass.substring(9)},[]);const{codeData,languages,sdkTypes,isSinglePlainCommand}=useMemo(()=>{const childrenArray=Children.toArray(children);const languages=[];const sdkTypes=new Set;const codeData=[];const isSinglePlainCommand=childrenArray.length===1&&["language-shell","language-text"].some(lang=>isValidElement(childrenArray[0])&&isValidElement(childrenArray[0].props.children)&&childrenArray[0].props.children.props.className?.includes(lang));childrenArray.forEach(child=>{if(!isValidElement(child))return;const preElement=child;const codeElement=isValidElement(preElement.props.children)?preElement.props.children:null;if(!codeElement)return;const codeLanguage=extractLanguageFromCode(codeElement);if(!codeLanguage)return;if(codeLanguage.startsWith("realtime_")){sdkTypes.add("realtime")}else if(codeLanguage.startsWith("rest_")){sdkTypes.add("rest")}if(!languages.includes(codeLanguage)){languages.push(codeLanguage)}const codeContent=codeElement.props.children;codeData.push({language:codeLanguage,content:codeContent})});return{codeData,languages,sdkTypes,isSinglePlainCommand}},[children,extractLanguageFromCode]);const showSDKSelector=sdkTypes.size>0;const filteredLanguages=useMemo(()=>{const filtered=!sdk||!showSDKSelector?[...languages]:languages.filter(lang=>lang.startsWith(`${sdk}_`));if(languageOrdering&&languageOrdering.length>0){filtered.sort((a,b)=>{const aBase=stripSdkType(a);const bBase=stripSdkType(b);const aIndex=languageOrdering.indexOf(aBase);const bIndex=languageOrdering.indexOf(bBase);if(aIndex!==-1&&bIndex!==-1)return aIndex-bIndex;if(aIndex!==-1)return-1;if(bIndex!==-1)return 1;return 0})}return filtered},[sdk,showSDKSelector,languages,languageOrdering]);const activeLanguage=useMemo(()=>{if(sdk&&sdkTypes.has(sdk)){return`${sdk}_${lang}`}if(lang)return lang;if(filteredLanguages.length>0)return filteredLanguages[0];return languages[0]},[lang,sdk,sdkTypes,filteredLanguages]);const requiresApiKeySubstitution=useMemo(()=>{const containsPlaceholder=codeData.some(code=>code?.content.includes("{{API_KEY}}")&&code?.language===lang);return containsPlaceholder&&!!apiKeys&&apiKeys.length>0&&!!selectedApiKey},[codeData,apiKeys,selectedApiKey,lang]);const[isHovering,setIsHovering]=useState(false);const hasOnlyJsonSnippet=useMemo(()=>languages.length===1&&languages[0]==="json",[languages]);const processedChildren=useMemo(()=>{if(!activeLanguage)return[];const targetLanguage=hasOnlyJsonSnippet?"json":activeLanguage;return codeData.filter(code=>{return code?.language===targetLanguage}).map(code=>{if(!code)return null;const cleanLang=hasOnlyJsonSnippet?"json":code.language;const langInfo=getLanguageInfo(cleanLang??"");if(typeof code.content==="string"||typeof code.content==="number"||typeof code.content==="boolean"){let processedContent=String(code.content);if(requiresApiKeySubstitution){processedContent=substituteApiKey(processedContent,selectedApiKey)}if(!langInfo.syntaxHighlighterKey||!cleanLang)return null;return React.createElement(Code,{key:code.language,language:langInfo.syntaxHighlighterKey||cleanLang,snippet:processedContent,additionalCSS:"bg-neutral-100 text-neutral-1300 dark:bg-neutral-1200 dark:text-neutral-200 px-6 py-4",showLines:showCodeLines})}return null})},[activeLanguage,codeData,hasOnlyJsonSnippet,showCodeLines,apiKeys,selectedApiKey]);const hasSnippetForActiveLanguage=useMemo(()=>{if(!activeLanguage)return false;if(hasOnlyJsonSnippet)return true;return codeData.some(code=>{return code?.language===activeLanguage})},[activeLanguage,hasOnlyJsonSnippet,codeData]);const handleSDKTypeChange=useCallback(type=>{const nextLang=stripSdkType(languages.find(l=>l===`${type}_${stripSdkType(activeLanguage)}`)??languages.find(l=>l.startsWith(`${type}_`))??activeLanguage);if(onChange&&nextLang){onChange(stripSdkType(activeLanguage),type)}},[languages]);const handleLanguageChange=useCallback(language=>{if(onChange){onChange(stripSdkType(language),sdk)}},[onChange,sdk]);const NoSnippetMessage=useMemo(()=>{if(!activeLanguage)return()=>null;const activeLanguageInfo=getLanguageInfo(activeLanguage);return()=>React.createElement("div",{className:"px-16 py-6 ui-text-body2 text-neutral-800 dark:text-neutral-400 text-center flex flex-col gap-3 items-center"},React.createElement(Icon,{name:"icon-gui-exclamation-triangle-outline",color:"text-yellow-600 dark:text-yellow-400",size:"24px"}),React.createElement("p",{className:"ui-text-p3 text-neutral-700 dark:text-neutral-600"},"You're currently viewing the ",activeLanguageInfo.label," docs. There either isn't a ",activeLanguageInfo.label," code sample for this example, or this feature isn't supported in"," ",activeLanguageInfo.label,". Switch language to view this example in a different language, or check which SDKs support this feature."))},[activeLanguage]);const showLanguageSelector=!fixed&&filteredLanguages.length>0;const showFullSelector=filteredLanguages.length>1;const renderContent=useMemo(()=>{if(!activeLanguage)return null;if(hasSnippetForActiveLanguage){return processedChildren}return React.createElement(NoSnippetMessage,null)},[activeLanguage,hasSnippetForActiveLanguage,processedChildren,NoSnippetMessage]);if(isSinglePlainCommand){const plainChild=codeData[0];if(plainChild){const codeContent=plainChild.content;const language=plainChild.language;if(!language||!codeContent)return null;let processedContent=String(codeContent);if(requiresApiKeySubstitution){processedContent=substituteApiKey(processedContent,selectedApiKey)}return React.createElement(PlainCodeView,{content:processedContent,className:className,language:language,icon:language==="shell"?"icon-gui-command-line-outline":null})}}return React.createElement("div",{className:cn("rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-1200 border border-neutral-300 dark:border-neutral-1000 min-h-[3.375rem]",className)},headerRow&&React.createElement("div",{className:"h-[2.375rem] bg-neutral-200 dark:bg-neutral-1100 border-b border-neutral-300 dark:border-neutral-1000 flex items-center py-1 px-3 rounded-t-lg"},React.createElement("div",{className:"flex space-x-1.5"},React.createElement("div",{className:"w-3 h-3 rounded-full bg-orange-500"}),React.createElement("div",{className:"w-3 h-3 rounded-full bg-yellow-500"}),React.createElement("div",{className:"w-3 h-3 rounded-full bg-green-500"})),React.createElement("div",{className:"flex-1 text-center ui-text-p3 font-bold text-neutral-1300 dark:text-neutral-000"},title),React.createElement("div",{className:"w-12"})),showSDKSelector&&React.createElement("div",{className:cn("p-2 border-b border-neutral-200 dark:border-neutral-1100 h-14",headerRow?"":"rounded-t-lg")},React.createElement("div",{className:"flex gap-3 justify-start"},sdkTypes.has("realtime")&&React.createElement(TooltipButton,{tooltip:"Realtime SDK",active:sdk==="realtime",onClick:()=>handleSDKTypeChange("realtime"),variant:"segmented",size:"sm",alwaysShowLabel:true},"Realtime"),sdkTypes.has("rest")&&React.createElement(TooltipButton,{tooltip:"REST SDK",active:sdk==="rest",onClick:()=>handleSDKTypeChange("rest"),variant:"segmented",size:"sm",alwaysShowLabel:true},"REST"))),showLanguageSelector&&(showFullSelector?React.createElement(LanguageSelector,{languages:filteredLanguages,activeLanguage:activeLanguage,onLanguageChange:handleLanguageChange}):React.createElement("div",{className:cn("border-b border-neutral-200 dark:border-neutral-1100 h-[2.125rem] inline-flex items-center px-3 w-full",{"rounded-t-lg":!headerRow})},filteredLanguages.length>0&&React.createElement("div",{className:cn("inline-flex items-center",{"cursor-pointer":filteredLanguages.length>0}),...filteredLanguages.length>0&&{onClick:()=>handleLanguageChange(filteredLanguages[0])}},React.createElement(Icon,{name:getLanguageInfo(filteredLanguages[0]).icon,size:"16px",additionalCSS:"mr-2"}),React.createElement("span",{className:"ui-text-label4 font-semibold text-neutral-800 dark:text-neutral-500 select-none"},getLanguageInfo(filteredLanguages[0]).label)))),React.createElement("div",{ref:codeRef,className:"relative",onMouseEnter:()=>setIsHovering(true),onMouseLeave:()=>setIsHovering(false),onFocus:()=>setIsHovering(true),onBlur:()=>setIsHovering(false),tabIndex:0},renderContent,isHovering&&activeLanguage&&React.createElement(CopyButton,{onCopy:()=>{const text=codeData.find(code=>code.language===activeLanguage)?.content;if(text)copy(substituteApiKey(text,selectedApiKey,false))},isCopied:isCopied})),requiresApiKeySubstitution&&React.createElement(ApiKeySelector,{apiKeys:apiKeys,selectedApiKey:selectedApiKey,onApiKeyChange:setSelectedApiKey}))};export default CodeSnippet;
|
|
1
|
+
import React,{useState,useEffect,Children,isValidElement,useRef,useCallback,useMemo}from"react";import Code from"./Code";import cn from"./utils/cn";import Icon from"./Icon";import{getLanguageInfo,stripSdkType}from"./CodeSnippet/languages";import LanguageSelector from"./CodeSnippet/LanguageSelector";import ApiKeySelector from"./CodeSnippet/ApiKeySelector";import useCopyToClipboard from"./utils/useCopyToClipboard";import PlainCodeView from"./CodeSnippet/PlainCodeView";import CopyButton from"./CodeSnippet/CopyButton";import TooltipButton from"./CodeSnippet/TooltipButton";const substituteApiKey=(content,apiKey,mask=true)=>{return content.replace(/\{\{API_KEY\}\}/g,mask?`${apiKey.split(":")[0]}:*****`:apiKey)};const CodeSnippet=({fixed=false,headerRow=false,title="Code",children,className,lang,onChange,apiKeys,sdk,showCodeLines=true,languageOrdering})=>{const codeRef=useRef(null);const{isCopied,copy}=useCopyToClipboard();const[selectedApiKey,setSelectedApiKey]=useState(()=>apiKeys?.[0]?.keys?.[0]?.key??"");useEffect(()=>{if(!selectedApiKey&&apiKeys&&apiKeys.length>0){setSelectedApiKey(apiKeys[0].keys?.[0]?.key)}},[apiKeys,selectedApiKey]);useEffect(()=>{const element=codeRef.current;if(!element)return;const unmaskRenderedApiKey=(content,apiKey)=>{return content.replace(/(['"]?)([^:'"]+):\*{5}\1/g,`$1${apiKey}$1`)};const handleCopy=event=>{const selection=window.getSelection();if(!selection||selection.rangeCount===0)return;const selectedText=selection.toString();if(!selectedText)return;const range=selection.getRangeAt(0);if(!element.contains(range.commonAncestorContainer))return;const modifiedText=unmaskRenderedApiKey(selectedText,selectedApiKey);event.clipboardData?.setData("text/plain",modifiedText);event.preventDefault()};document.addEventListener("copy",handleCopy);return()=>{document.removeEventListener("copy",handleCopy)}},[codeRef.current,selectedApiKey]);const extractLanguageFromCode=useCallback(codeElement=>{if(!codeElement||!codeElement.props.className)return null;const classNames=codeElement.props.className.split(" ");const langClass=classNames.find(cls=>cls.startsWith("language-"));if(!langClass)return null;return langClass.substring(9)},[]);const{codeData,languages,sdkTypes,isSinglePlainCommand}=useMemo(()=>{const childrenArray=Children.toArray(children);const languages=[];const sdkTypes=new Set;const codeData=[];const isSinglePlainCommand=childrenArray.length===1&&["language-shell","language-text"].some(lang=>isValidElement(childrenArray[0])&&isValidElement(childrenArray[0].props.children)&&childrenArray[0].props.children.props.className?.includes(lang));childrenArray.forEach(child=>{if(!isValidElement(child))return;const preElement=child;const codeElement=isValidElement(preElement.props.children)?preElement.props.children:null;if(!codeElement)return;const codeLanguage=extractLanguageFromCode(codeElement);if(!codeLanguage)return;if(codeLanguage.startsWith("realtime_")){sdkTypes.add("realtime")}else if(codeLanguage.startsWith("rest_")){sdkTypes.add("rest")}if(!languages.includes(codeLanguage)){languages.push(codeLanguage)}const codeContent=codeElement.props.children;codeData.push({language:codeLanguage,content:codeContent})});return{codeData,languages,sdkTypes,isSinglePlainCommand}},[children,extractLanguageFromCode]);const showSDKSelector=sdkTypes.size>0;const filteredLanguages=useMemo(()=>{const filtered=!sdk||!showSDKSelector?[...languages]:languages.filter(lang=>lang.startsWith(`${sdk}_`));if(languageOrdering&&languageOrdering.length>0){filtered.sort((a,b)=>{const aBase=stripSdkType(a);const bBase=stripSdkType(b);const aIndex=languageOrdering.indexOf(aBase);const bIndex=languageOrdering.indexOf(bBase);if(aIndex!==-1&&bIndex!==-1)return aIndex-bIndex;if(aIndex!==-1)return-1;if(bIndex!==-1)return 1;return 0})}return filtered},[sdk,showSDKSelector,languages,languageOrdering]);const activeLanguage=useMemo(()=>{if(sdk&&sdkTypes.has(sdk)){return`${sdk}_${lang}`}if(lang)return lang;if(filteredLanguages.length>0)return filteredLanguages[0];return languages[0]},[lang,sdk,sdkTypes,filteredLanguages]);const requiresApiKeySubstitution=useMemo(()=>{const containsPlaceholder=codeData.some(code=>code?.content.includes("{{API_KEY}}")&&stripSdkType(code?.language)===lang);return containsPlaceholder&&!!apiKeys&&apiKeys.length>0&&!!selectedApiKey},[codeData,apiKeys,selectedApiKey,lang]);const[isHovering,setIsHovering]=useState(false);const hasOnlyJsonSnippet=useMemo(()=>languages.length===1&&languages[0]==="json",[languages]);const processedChildren=useMemo(()=>{if(!activeLanguage)return[];const targetLanguage=hasOnlyJsonSnippet?"json":activeLanguage;return codeData.filter(code=>{return code?.language===targetLanguage}).map(code=>{if(!code)return null;const cleanLang=hasOnlyJsonSnippet?"json":code.language;const langInfo=getLanguageInfo(cleanLang??"");if(typeof code.content==="string"||typeof code.content==="number"||typeof code.content==="boolean"){let processedContent=String(code.content);if(requiresApiKeySubstitution){processedContent=substituteApiKey(processedContent,selectedApiKey)}if(!langInfo.syntaxHighlighterKey||!cleanLang)return null;return React.createElement(Code,{key:code.language,language:langInfo.syntaxHighlighterKey||cleanLang,snippet:processedContent,additionalCSS:"bg-neutral-100 text-neutral-1300 dark:bg-neutral-1200 dark:text-neutral-200 px-6 py-4",showLines:showCodeLines})}return null})},[activeLanguage,codeData,hasOnlyJsonSnippet,showCodeLines,apiKeys,selectedApiKey]);const hasSnippetForActiveLanguage=useMemo(()=>{if(!activeLanguage)return false;if(hasOnlyJsonSnippet)return true;return codeData.some(code=>{return code?.language===activeLanguage})},[activeLanguage,hasOnlyJsonSnippet,codeData]);const handleSDKTypeChange=useCallback(type=>{const nextLang=stripSdkType(languages.find(l=>l===`${type}_${stripSdkType(activeLanguage)}`)??languages.find(l=>l.startsWith(`${type}_`))??activeLanguage);if(onChange&&nextLang){onChange(stripSdkType(activeLanguage),type)}},[languages]);const handleLanguageChange=useCallback(language=>{if(onChange){onChange(stripSdkType(language),sdk)}},[onChange,sdk]);const NoSnippetMessage=useMemo(()=>{if(!activeLanguage)return()=>null;const activeLanguageInfo=getLanguageInfo(activeLanguage);return()=>React.createElement("div",{className:"px-16 py-6 ui-text-body2 text-neutral-800 dark:text-neutral-400 text-center flex flex-col gap-3 items-center"},React.createElement(Icon,{name:"icon-gui-exclamation-triangle-outline",color:"text-yellow-600 dark:text-yellow-400",size:"24px"}),React.createElement("p",{className:"ui-text-p3 text-neutral-700 dark:text-neutral-600"},"You're currently viewing the ",activeLanguageInfo.label," docs. There either isn't a ",activeLanguageInfo.label," code sample for this example, or this feature isn't supported in"," ",activeLanguageInfo.label,". Switch language to view this example in a different language, or check which SDKs support this feature."))},[activeLanguage]);const showLanguageSelector=!fixed&&filteredLanguages.length>0;const showFullSelector=filteredLanguages.length>1;const renderContent=useMemo(()=>{if(!activeLanguage)return null;if(hasSnippetForActiveLanguage){return processedChildren}return React.createElement(NoSnippetMessage,null)},[activeLanguage,hasSnippetForActiveLanguage,processedChildren,NoSnippetMessage]);if(isSinglePlainCommand){const plainChild=codeData[0];if(plainChild){const codeContent=plainChild.content;const language=plainChild.language;if(!language||!codeContent)return null;let processedContent=String(codeContent);if(requiresApiKeySubstitution){processedContent=substituteApiKey(processedContent,selectedApiKey)}return React.createElement(PlainCodeView,{content:processedContent,className:className,language:language,icon:language==="shell"?"icon-gui-command-line-outline":null})}}return React.createElement("div",{className:cn("rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-1200 border border-neutral-300 dark:border-neutral-1000 min-h-[3.375rem]",className)},headerRow&&React.createElement("div",{className:"h-[2.375rem] bg-neutral-200 dark:bg-neutral-1100 border-b border-neutral-300 dark:border-neutral-1000 flex items-center py-1 px-3 rounded-t-lg"},React.createElement("div",{className:"flex space-x-1.5"},React.createElement("div",{className:"w-3 h-3 rounded-full bg-orange-500"}),React.createElement("div",{className:"w-3 h-3 rounded-full bg-yellow-500"}),React.createElement("div",{className:"w-3 h-3 rounded-full bg-green-500"})),React.createElement("div",{className:"flex-1 text-center ui-text-p3 font-bold text-neutral-1300 dark:text-neutral-000"},title),React.createElement("div",{className:"w-12"})),showSDKSelector&&React.createElement("div",{className:cn("p-2 border-b border-neutral-200 dark:border-neutral-1100 h-14",headerRow?"":"rounded-t-lg")},React.createElement("div",{className:"flex gap-3 justify-start"},sdkTypes.has("realtime")&&React.createElement(TooltipButton,{tooltip:"Realtime SDK",active:sdk==="realtime",onClick:()=>handleSDKTypeChange("realtime"),variant:"segmented",size:"sm",alwaysShowLabel:true},"Realtime"),sdkTypes.has("rest")&&React.createElement(TooltipButton,{tooltip:"REST SDK",active:sdk==="rest",onClick:()=>handleSDKTypeChange("rest"),variant:"segmented",size:"sm",alwaysShowLabel:true},"REST"))),showLanguageSelector&&(showFullSelector?React.createElement(LanguageSelector,{languages:filteredLanguages,activeLanguage:activeLanguage,onLanguageChange:handleLanguageChange}):React.createElement("div",{className:cn("border-b border-neutral-200 dark:border-neutral-1100 h-[2.125rem] inline-flex items-center px-3 w-full",{"rounded-t-lg":!headerRow})},filteredLanguages.length>0&&React.createElement("div",{className:cn("inline-flex items-center",{"cursor-pointer":filteredLanguages.length>0}),...filteredLanguages.length>0&&{onClick:()=>handleLanguageChange(filteredLanguages[0])}},React.createElement(Icon,{name:getLanguageInfo(filteredLanguages[0]).icon,size:"16px",additionalCSS:"mr-2"}),React.createElement("span",{className:"ui-text-label4 font-semibold text-neutral-800 dark:text-neutral-500 select-none"},getLanguageInfo(filteredLanguages[0]).label)))),React.createElement("div",{ref:codeRef,className:"relative",onMouseEnter:()=>setIsHovering(true),onMouseLeave:()=>setIsHovering(false),onFocus:()=>setIsHovering(true),onBlur:()=>setIsHovering(false),tabIndex:0},renderContent,isHovering&&activeLanguage&&React.createElement(CopyButton,{onCopy:()=>{const text=codeData.find(code=>code.language===activeLanguage)?.content;if(text)copy(substituteApiKey(text,selectedApiKey,false))},isCopied:isCopied})),requiresApiKeySubstitution&&React.createElement(ApiKeySelector,{apiKeys:apiKeys,selectedApiKey:selectedApiKey,onApiKeyChange:setSelectedApiKey}))};export default CodeSnippet;
|
|
2
2
|
//# sourceMappingURL=CodeSnippet.js.map
|
package/core/CodeSnippet.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/CodeSnippet.tsx"],"sourcesContent":["import React, {\n useState,\n useEffect,\n Children,\n isValidElement,\n useRef,\n useCallback,\n useMemo,\n} from \"react\";\nimport Code from \"./Code\";\nimport cn from \"./utils/cn\";\nimport Icon from \"./Icon\";\nimport { getLanguageInfo, stripSdkType } from \"./CodeSnippet/languages\";\nimport LanguageSelector from \"./CodeSnippet/LanguageSelector\";\nimport ApiKeySelector from \"./CodeSnippet/ApiKeySelector\";\nimport useCopyToClipboard from \"./utils/useCopyToClipboard\";\nimport PlainCodeView from \"./CodeSnippet/PlainCodeView\";\nimport CopyButton from \"./CodeSnippet/CopyButton\";\nimport TooltipButton from \"./CodeSnippet/TooltipButton\";\n\n// Define SDK type\nexport type SDKType = \"realtime\" | \"rest\" | null;\n\n// Define API key types\nexport type ApiKeysItem = {\n app: string;\n keys: { name: string; key: string }[];\n};\n\nexport type CodeSnippetProps = {\n /**\n * If true, hides the language selector row completely\n */\n fixed?: boolean;\n /**\n * If true, renders a macOS-style window header with buttons and title\n */\n headerRow?: boolean;\n /**\n * Title to display in the header row (when headerRow is true)\n */\n title?: string;\n /**\n * Children elements with lang attribute\n */\n children: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n /**\n * Default language to display. If not found in available languages, first available is used.\n * If found in languages but no matching snippet exists, a message is displayed.\n */\n lang: string | null;\n /**\n * Callback fired when the active language changes\n */\n onChange?: (language: string, sdk?: SDKType) => void;\n /**\n * List of API keys to display in a dropdown\n */\n apiKeys?: ApiKeysItem[];\n /**\n * Default SDK type to use for the code snippet\n */\n sdk?: SDKType;\n /**\n * Whether to show line numbers in code snippets\n */\n showCodeLines?: boolean;\n /**\n * Defines the order in which languages should be displayed.\n * Languages not in this array will be shown after those that are included.\n */\n languageOrdering?: string[];\n};\n\n// Substitution function for API key placeholders\nconst substituteApiKey = (\n content: string,\n apiKey: string,\n mask = true,\n): string => {\n return content.replace(\n /\\{\\{API_KEY\\}\\}/g,\n mask ? `${apiKey.split(\":\")[0]}:*****` : apiKey,\n );\n};\n\n/**\n * CodeSnippet component that displays code with language switching capability\n */\nconst CodeSnippet: React.FC<CodeSnippetProps> = ({\n fixed = false,\n headerRow = false,\n title = \"Code\",\n children,\n className,\n lang,\n onChange,\n apiKeys,\n sdk,\n showCodeLines = true,\n languageOrdering,\n}) => {\n const codeRef = useRef<HTMLDivElement>(null);\n const { isCopied, copy } = useCopyToClipboard();\n\n const [selectedApiKey, setSelectedApiKey] = useState<string>(\n () => apiKeys?.[0]?.keys?.[0]?.key ?? \"\",\n );\n\n useEffect(() => {\n if (!selectedApiKey && apiKeys && apiKeys.length > 0) {\n setSelectedApiKey(apiKeys[0].keys?.[0]?.key);\n }\n }, [apiKeys, selectedApiKey]);\n\n useEffect(() => {\n const element = codeRef.current;\n if (!element) return;\n\n // Detects the key masking via substituteApiKey (i.e. \"abcde:*****\") and replaces it with the actual API key\n const unmaskRenderedApiKey = (content: string, apiKey: string): string => {\n return content.replace(/(['\"]?)([^:'\"]+):\\*{5}\\1/g, `$1${apiKey}$1`);\n };\n\n const handleCopy = (event: ClipboardEvent) => {\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n\n const selectedText = selection.toString();\n if (!selectedText) return;\n\n // Check if the selection is within our element\n const range = selection.getRangeAt(0);\n if (!element.contains(range.commonAncestorContainer)) return;\n\n const modifiedText = unmaskRenderedApiKey(selectedText, selectedApiKey);\n\n event.clipboardData?.setData(\"text/plain\", modifiedText);\n event.preventDefault();\n };\n\n document.addEventListener(\"copy\", handleCopy);\n\n return () => {\n document.removeEventListener(\"copy\", handleCopy);\n };\n }, [codeRef.current, selectedApiKey]);\n\n const extractLanguageFromCode = useCallback(\n (codeElement: React.ReactElement | null): string | null => {\n if (!codeElement || !codeElement.props.className) return null;\n\n const classNames = codeElement.props.className.split(\" \");\n const langClass = classNames.find((cls: string) =>\n cls.startsWith(\"language-\"),\n );\n if (!langClass) return null;\n\n return langClass.substring(9); // Remove \"language-\" prefix\n },\n [],\n );\n\n const { codeData, languages, sdkTypes, isSinglePlainCommand } =\n useMemo(() => {\n const childrenArray = Children.toArray(children);\n const languages: string[] = [];\n const sdkTypes = new Set<SDKType>();\n const codeData: { language: string; content: string }[] = [];\n\n const isSinglePlainCommand =\n childrenArray.length === 1 &&\n [\"language-shell\", \"language-text\"].some(\n (lang) =>\n isValidElement(childrenArray[0]) &&\n isValidElement(childrenArray[0].props.children) &&\n childrenArray[0].props.children.props.className?.includes(lang),\n );\n\n childrenArray.forEach((child) => {\n if (!isValidElement(child)) return;\n\n const preElement = child;\n const codeElement = isValidElement(preElement.props.children)\n ? preElement.props.children\n : null;\n\n if (!codeElement) return;\n\n const codeLanguage = extractLanguageFromCode(codeElement);\n\n if (!codeLanguage) return;\n\n if (codeLanguage.startsWith(\"realtime_\")) {\n sdkTypes.add(\"realtime\");\n } else if (codeLanguage.startsWith(\"rest_\")) {\n sdkTypes.add(\"rest\");\n }\n\n if (!languages.includes(codeLanguage)) {\n languages.push(codeLanguage);\n }\n\n const codeContent = codeElement.props.children;\n codeData.push({ language: codeLanguage, content: codeContent });\n });\n\n return {\n codeData,\n languages,\n sdkTypes,\n isSinglePlainCommand,\n };\n }, [children, extractLanguageFromCode]);\n\n const showSDKSelector = sdkTypes.size > 0;\n\n const filteredLanguages = useMemo(() => {\n const filtered =\n !sdk || !showSDKSelector\n ? [...languages]\n : languages.filter((lang) => lang.startsWith(`${sdk}_`));\n\n // Apply custom ordering if provided\n if (languageOrdering && languageOrdering.length > 0) {\n filtered.sort((a, b) => {\n const aBase = stripSdkType(a);\n const bBase = stripSdkType(b);\n\n const aIndex = languageOrdering.indexOf(aBase);\n const bIndex = languageOrdering.indexOf(bBase);\n\n if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;\n if (aIndex !== -1) return -1;\n if (bIndex !== -1) return 1;\n return 0;\n });\n }\n\n return filtered;\n }, [sdk, showSDKSelector, languages, languageOrdering]);\n\n const activeLanguage = useMemo(() => {\n if (sdk && sdkTypes.has(sdk)) {\n return `${sdk}_${lang}`;\n }\n\n if (lang) return lang;\n\n if (filteredLanguages.length > 0) return filteredLanguages[0];\n\n return languages[0];\n }, [lang, sdk, sdkTypes, filteredLanguages]);\n\n const requiresApiKeySubstitution = useMemo(() => {\n const containsPlaceholder = codeData.some(\n (code) =>\n code?.content.includes(\"{{API_KEY}}\") && code?.language === lang,\n );\n\n return (\n containsPlaceholder && !!apiKeys && apiKeys.length > 0 && !!selectedApiKey\n );\n }, [codeData, apiKeys, selectedApiKey, lang]);\n\n const [isHovering, setIsHovering] = useState(false);\n\n const hasOnlyJsonSnippet = useMemo(\n () => languages.length === 1 && languages[0] === \"json\",\n [languages],\n );\n\n const processedChildren = useMemo(() => {\n if (!activeLanguage) return [];\n\n const targetLanguage = hasOnlyJsonSnippet ? \"json\" : activeLanguage;\n\n return codeData\n .filter((code) => {\n return code?.language === targetLanguage;\n })\n .map((code) => {\n if (!code) return null;\n\n const cleanLang = hasOnlyJsonSnippet ? \"json\" : code.language;\n const langInfo = getLanguageInfo(cleanLang ?? \"\");\n\n if (\n typeof code.content === \"string\" ||\n typeof code.content === \"number\" ||\n typeof code.content === \"boolean\"\n ) {\n // Apply API key substitution if apiKeys are provided\n let processedContent = String(code.content);\n if (requiresApiKeySubstitution) {\n processedContent = substituteApiKey(\n processedContent,\n selectedApiKey,\n );\n }\n\n if (!langInfo.syntaxHighlighterKey || !cleanLang) return null;\n\n return (\n <Code\n key={code.language}\n language={langInfo.syntaxHighlighterKey || cleanLang}\n snippet={processedContent}\n additionalCSS=\"bg-neutral-100 text-neutral-1300 dark:bg-neutral-1200 dark:text-neutral-200 px-6 py-4\"\n showLines={showCodeLines}\n />\n );\n }\n\n return null;\n });\n }, [\n activeLanguage,\n codeData,\n hasOnlyJsonSnippet,\n showCodeLines,\n apiKeys,\n selectedApiKey,\n ]);\n\n const hasSnippetForActiveLanguage = useMemo(() => {\n if (!activeLanguage) return false;\n if (hasOnlyJsonSnippet) return true;\n\n return codeData.some((code) => {\n return code?.language === activeLanguage;\n });\n }, [activeLanguage, hasOnlyJsonSnippet, codeData]);\n\n const handleSDKTypeChange = useCallback(\n (type: SDKType) => {\n const nextLang = stripSdkType(\n languages.find(\n (l) => l === `${type}_${stripSdkType(activeLanguage)}`,\n ) ??\n languages.find((l) => l.startsWith(`${type}_`)) ??\n activeLanguage,\n );\n\n if (onChange && nextLang) {\n onChange(stripSdkType(activeLanguage), type);\n }\n },\n [languages],\n );\n\n const handleLanguageChange = useCallback(\n (language: string) => {\n if (onChange) {\n onChange(stripSdkType(language), sdk);\n }\n },\n [onChange, sdk],\n );\n\n const NoSnippetMessage = useMemo(() => {\n if (!activeLanguage) return () => null;\n\n const activeLanguageInfo = getLanguageInfo(activeLanguage);\n\n return () => (\n <div className=\"px-16 py-6 ui-text-body2 text-neutral-800 dark:text-neutral-400 text-center flex flex-col gap-3 items-center\">\n <Icon\n name=\"icon-gui-exclamation-triangle-outline\"\n color=\"text-yellow-600 dark:text-yellow-400\"\n size=\"24px\"\n />\n <p className=\"ui-text-p3 text-neutral-700 dark:text-neutral-600\">\n You're currently viewing the {activeLanguageInfo.label} docs.\n There either isn't a {activeLanguageInfo.label} code sample for\n this example, or this feature isn't supported in{\" \"}\n {activeLanguageInfo.label}. Switch language to view this example in a\n different language, or check which SDKs support this feature.\n </p>\n </div>\n );\n }, [activeLanguage]);\n\n const showLanguageSelector = !fixed && filteredLanguages.length > 0;\n const showFullSelector = filteredLanguages.length > 1;\n\n const renderContent = useMemo(() => {\n if (!activeLanguage) return null;\n\n if (hasSnippetForActiveLanguage) {\n return processedChildren;\n }\n\n return <NoSnippetMessage />;\n }, [\n activeLanguage,\n hasSnippetForActiveLanguage,\n processedChildren,\n NoSnippetMessage,\n ]);\n\n // Render special case for plain commands (shell or text)\n if (isSinglePlainCommand) {\n const plainChild = codeData[0];\n if (plainChild) {\n const codeContent = plainChild.content;\n const language = plainChild.language;\n\n if (!language || !codeContent) return null;\n\n // Apply API key substitution if apiKeys are provided\n let processedContent = String(codeContent);\n if (requiresApiKeySubstitution) {\n processedContent = substituteApiKey(processedContent, selectedApiKey);\n }\n\n return (\n <PlainCodeView\n content={processedContent}\n className={className}\n language={language}\n icon={language === \"shell\" ? \"icon-gui-command-line-outline\" : null}\n />\n );\n }\n }\n\n return (\n <div\n className={cn(\n \"rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-1200 border border-neutral-300 dark:border-neutral-1000 min-h-[3.375rem]\",\n className,\n )}\n >\n {headerRow && (\n <div className=\"h-[2.375rem] bg-neutral-200 dark:bg-neutral-1100 border-b border-neutral-300 dark:border-neutral-1000 flex items-center py-1 px-3 rounded-t-lg\">\n <div className=\"flex space-x-1.5\">\n <div className=\"w-3 h-3 rounded-full bg-orange-500\"></div>\n <div className=\"w-3 h-3 rounded-full bg-yellow-500\"></div>\n <div className=\"w-3 h-3 rounded-full bg-green-500\"></div>\n </div>\n\n <div className=\"flex-1 text-center ui-text-p3 font-bold text-neutral-1300 dark:text-neutral-000\">\n {title}\n </div>\n\n {/* Empty div for balance */}\n <div className=\"w-12\"></div>\n </div>\n )}\n {showSDKSelector && (\n <div\n className={cn(\n \"p-2 border-b border-neutral-200 dark:border-neutral-1100 h-14\",\n headerRow ? \"\" : \"rounded-t-lg\",\n )}\n >\n <div className=\"flex gap-3 justify-start\">\n {sdkTypes.has(\"realtime\") && (\n <TooltipButton\n tooltip=\"Realtime SDK\"\n active={sdk === \"realtime\"}\n onClick={() => handleSDKTypeChange(\"realtime\")}\n variant=\"segmented\"\n size=\"sm\"\n alwaysShowLabel={true}\n >\n Realtime\n </TooltipButton>\n )}\n\n {sdkTypes.has(\"rest\") && (\n <TooltipButton\n tooltip=\"REST SDK\"\n active={sdk === \"rest\"}\n onClick={() => handleSDKTypeChange(\"rest\")}\n variant=\"segmented\"\n size=\"sm\"\n alwaysShowLabel={true}\n >\n REST\n </TooltipButton>\n )}\n </div>\n </div>\n )}\n\n {showLanguageSelector &&\n (showFullSelector ? (\n <LanguageSelector\n languages={filteredLanguages}\n activeLanguage={activeLanguage}\n onLanguageChange={handleLanguageChange}\n />\n ) : (\n <div\n className={cn(\n \"border-b border-neutral-200 dark:border-neutral-1100 h-[2.125rem] inline-flex items-center px-3 w-full\",\n { \"rounded-t-lg\": !headerRow },\n )}\n >\n {filteredLanguages.length > 0 && (\n <div\n className={cn(\"inline-flex items-center\", {\n \"cursor-pointer\": filteredLanguages.length > 0,\n })}\n {...(filteredLanguages.length > 0 && {\n onClick: () => handleLanguageChange(filteredLanguages[0]),\n })}\n >\n <Icon\n name={getLanguageInfo(filteredLanguages[0]).icon}\n size=\"16px\"\n additionalCSS=\"mr-2\"\n />\n <span className=\"ui-text-label4 font-semibold text-neutral-800 dark:text-neutral-500 select-none\">\n {getLanguageInfo(filteredLanguages[0]).label}\n </span>\n </div>\n )}\n </div>\n ))}\n <div\n ref={codeRef}\n className=\"relative\"\n onMouseEnter={() => setIsHovering(true)}\n onMouseLeave={() => setIsHovering(false)}\n onFocus={() => setIsHovering(true)}\n onBlur={() => setIsHovering(false)}\n tabIndex={0}\n >\n {renderContent}\n {isHovering && activeLanguage && (\n <CopyButton\n onCopy={() => {\n const text = codeData.find(\n (code) => code.language === activeLanguage,\n )?.content;\n if (text) copy(substituteApiKey(text, selectedApiKey, false));\n }}\n isCopied={isCopied}\n />\n )}\n </div>\n {requiresApiKeySubstitution && (\n <ApiKeySelector\n apiKeys={apiKeys}\n selectedApiKey={selectedApiKey}\n onApiKeyChange={setSelectedApiKey}\n />\n )}\n </div>\n );\n};\n\nexport default CodeSnippet;\n"],"names":["React","useState","useEffect","Children","isValidElement","useRef","useCallback","useMemo","Code","cn","Icon","getLanguageInfo","stripSdkType","LanguageSelector","ApiKeySelector","useCopyToClipboard","PlainCodeView","CopyButton","TooltipButton","substituteApiKey","content","apiKey","mask","replace","split","CodeSnippet","fixed","headerRow","title","children","className","lang","onChange","apiKeys","sdk","showCodeLines","languageOrdering","codeRef","isCopied","copy","selectedApiKey","setSelectedApiKey","keys","key","length","element","current","unmaskRenderedApiKey","handleCopy","event","selection","window","getSelection","rangeCount","selectedText","toString","range","getRangeAt","contains","commonAncestorContainer","modifiedText","clipboardData","setData","preventDefault","document","addEventListener","removeEventListener","extractLanguageFromCode","codeElement","props","classNames","langClass","find","cls","startsWith","substring","codeData","languages","sdkTypes","isSinglePlainCommand","childrenArray","toArray","Set","some","includes","forEach","child","preElement","codeLanguage","add","push","codeContent","language","showSDKSelector","size","filteredLanguages","filtered","filter","sort","a","b","aBase","bBase","aIndex","indexOf","bIndex","activeLanguage","has","requiresApiKeySubstitution","containsPlaceholder","code","isHovering","setIsHovering","hasOnlyJsonSnippet","processedChildren","targetLanguage","map","cleanLang","langInfo","processedContent","String","syntaxHighlighterKey","snippet","additionalCSS","showLines","hasSnippetForActiveLanguage","handleSDKTypeChange","type","nextLang","l","handleLanguageChange","NoSnippetMessage","activeLanguageInfo","div","name","color","p","label","showLanguageSelector","showFullSelector","renderContent","plainChild","icon","tooltip","active","onClick","variant","alwaysShowLabel","onLanguageChange","span","ref","onMouseEnter","onMouseLeave","onFocus","onBlur","tabIndex","onCopy","text","onApiKeyChange"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/CodeSnippet.tsx"],"sourcesContent":["import React, {\n useState,\n useEffect,\n Children,\n isValidElement,\n useRef,\n useCallback,\n useMemo,\n} from \"react\";\nimport Code from \"./Code\";\nimport cn from \"./utils/cn\";\nimport Icon from \"./Icon\";\nimport { getLanguageInfo, stripSdkType } from \"./CodeSnippet/languages\";\nimport LanguageSelector from \"./CodeSnippet/LanguageSelector\";\nimport ApiKeySelector from \"./CodeSnippet/ApiKeySelector\";\nimport useCopyToClipboard from \"./utils/useCopyToClipboard\";\nimport PlainCodeView from \"./CodeSnippet/PlainCodeView\";\nimport CopyButton from \"./CodeSnippet/CopyButton\";\nimport TooltipButton from \"./CodeSnippet/TooltipButton\";\n\n// Define SDK type\nexport type SDKType = \"realtime\" | \"rest\" | null;\n\n// Define API key types\nexport type ApiKeysItem = {\n app: string;\n keys: { name: string; key: string }[];\n};\n\nexport type CodeSnippetProps = {\n /**\n * If true, hides the language selector row completely\n */\n fixed?: boolean;\n /**\n * If true, renders a macOS-style window header with buttons and title\n */\n headerRow?: boolean;\n /**\n * Title to display in the header row (when headerRow is true)\n */\n title?: string;\n /**\n * Children elements with lang attribute\n */\n children: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n /**\n * Default language to display. If not found in available languages, first available is used.\n * If found in languages but no matching snippet exists, a message is displayed.\n */\n lang: string | null;\n /**\n * Callback fired when the active language changes\n */\n onChange?: (language: string, sdk?: SDKType) => void;\n /**\n * List of API keys to display in a dropdown\n */\n apiKeys?: ApiKeysItem[];\n /**\n * Default SDK type to use for the code snippet\n */\n sdk?: SDKType;\n /**\n * Whether to show line numbers in code snippets\n */\n showCodeLines?: boolean;\n /**\n * Defines the order in which languages should be displayed.\n * Languages not in this array will be shown after those that are included.\n */\n languageOrdering?: string[];\n};\n\n// Substitution function for API key placeholders\nconst substituteApiKey = (\n content: string,\n apiKey: string,\n mask = true,\n): string => {\n return content.replace(\n /\\{\\{API_KEY\\}\\}/g,\n mask ? `${apiKey.split(\":\")[0]}:*****` : apiKey,\n );\n};\n\n/**\n * CodeSnippet component that displays code with language switching capability\n */\nconst CodeSnippet: React.FC<CodeSnippetProps> = ({\n fixed = false,\n headerRow = false,\n title = \"Code\",\n children,\n className,\n lang,\n onChange,\n apiKeys,\n sdk,\n showCodeLines = true,\n languageOrdering,\n}) => {\n const codeRef = useRef<HTMLDivElement>(null);\n const { isCopied, copy } = useCopyToClipboard();\n\n const [selectedApiKey, setSelectedApiKey] = useState<string>(\n () => apiKeys?.[0]?.keys?.[0]?.key ?? \"\",\n );\n\n useEffect(() => {\n if (!selectedApiKey && apiKeys && apiKeys.length > 0) {\n setSelectedApiKey(apiKeys[0].keys?.[0]?.key);\n }\n }, [apiKeys, selectedApiKey]);\n\n useEffect(() => {\n const element = codeRef.current;\n if (!element) return;\n\n // Detects the key masking via substituteApiKey (i.e. \"abcde:*****\") and replaces it with the actual API key\n const unmaskRenderedApiKey = (content: string, apiKey: string): string => {\n return content.replace(/(['\"]?)([^:'\"]+):\\*{5}\\1/g, `$1${apiKey}$1`);\n };\n\n const handleCopy = (event: ClipboardEvent) => {\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n\n const selectedText = selection.toString();\n if (!selectedText) return;\n\n // Check if the selection is within our element\n const range = selection.getRangeAt(0);\n if (!element.contains(range.commonAncestorContainer)) return;\n\n const modifiedText = unmaskRenderedApiKey(selectedText, selectedApiKey);\n\n event.clipboardData?.setData(\"text/plain\", modifiedText);\n event.preventDefault();\n };\n\n document.addEventListener(\"copy\", handleCopy);\n\n return () => {\n document.removeEventListener(\"copy\", handleCopy);\n };\n }, [codeRef.current, selectedApiKey]);\n\n const extractLanguageFromCode = useCallback(\n (codeElement: React.ReactElement | null): string | null => {\n if (!codeElement || !codeElement.props.className) return null;\n\n const classNames = codeElement.props.className.split(\" \");\n const langClass = classNames.find((cls: string) =>\n cls.startsWith(\"language-\"),\n );\n if (!langClass) return null;\n\n return langClass.substring(9); // Remove \"language-\" prefix\n },\n [],\n );\n\n const { codeData, languages, sdkTypes, isSinglePlainCommand } =\n useMemo(() => {\n const childrenArray = Children.toArray(children);\n const languages: string[] = [];\n const sdkTypes = new Set<SDKType>();\n const codeData: { language: string; content: string }[] = [];\n\n const isSinglePlainCommand =\n childrenArray.length === 1 &&\n [\"language-shell\", \"language-text\"].some(\n (lang) =>\n isValidElement(childrenArray[0]) &&\n isValidElement(childrenArray[0].props.children) &&\n childrenArray[0].props.children.props.className?.includes(lang),\n );\n\n childrenArray.forEach((child) => {\n if (!isValidElement(child)) return;\n\n const preElement = child;\n const codeElement = isValidElement(preElement.props.children)\n ? preElement.props.children\n : null;\n\n if (!codeElement) return;\n\n const codeLanguage = extractLanguageFromCode(codeElement);\n\n if (!codeLanguage) return;\n\n if (codeLanguage.startsWith(\"realtime_\")) {\n sdkTypes.add(\"realtime\");\n } else if (codeLanguage.startsWith(\"rest_\")) {\n sdkTypes.add(\"rest\");\n }\n\n if (!languages.includes(codeLanguage)) {\n languages.push(codeLanguage);\n }\n\n const codeContent = codeElement.props.children;\n codeData.push({ language: codeLanguage, content: codeContent });\n });\n\n return {\n codeData,\n languages,\n sdkTypes,\n isSinglePlainCommand,\n };\n }, [children, extractLanguageFromCode]);\n\n const showSDKSelector = sdkTypes.size > 0;\n\n const filteredLanguages = useMemo(() => {\n const filtered =\n !sdk || !showSDKSelector\n ? [...languages]\n : languages.filter((lang) => lang.startsWith(`${sdk}_`));\n\n // Apply custom ordering if provided\n if (languageOrdering && languageOrdering.length > 0) {\n filtered.sort((a, b) => {\n const aBase = stripSdkType(a);\n const bBase = stripSdkType(b);\n\n const aIndex = languageOrdering.indexOf(aBase);\n const bIndex = languageOrdering.indexOf(bBase);\n\n if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;\n if (aIndex !== -1) return -1;\n if (bIndex !== -1) return 1;\n return 0;\n });\n }\n\n return filtered;\n }, [sdk, showSDKSelector, languages, languageOrdering]);\n\n const activeLanguage = useMemo(() => {\n if (sdk && sdkTypes.has(sdk)) {\n return `${sdk}_${lang}`;\n }\n\n if (lang) return lang;\n\n if (filteredLanguages.length > 0) return filteredLanguages[0];\n\n return languages[0];\n }, [lang, sdk, sdkTypes, filteredLanguages]);\n\n const requiresApiKeySubstitution = useMemo(() => {\n const containsPlaceholder = codeData.some(\n (code) =>\n code?.content.includes(\"{{API_KEY}}\") &&\n stripSdkType(code?.language) === lang,\n );\n\n return (\n containsPlaceholder && !!apiKeys && apiKeys.length > 0 && !!selectedApiKey\n );\n }, [codeData, apiKeys, selectedApiKey, lang]);\n\n const [isHovering, setIsHovering] = useState(false);\n\n const hasOnlyJsonSnippet = useMemo(\n () => languages.length === 1 && languages[0] === \"json\",\n [languages],\n );\n\n const processedChildren = useMemo(() => {\n if (!activeLanguage) return [];\n\n const targetLanguage = hasOnlyJsonSnippet ? \"json\" : activeLanguage;\n\n return codeData\n .filter((code) => {\n return code?.language === targetLanguage;\n })\n .map((code) => {\n if (!code) return null;\n\n const cleanLang = hasOnlyJsonSnippet ? \"json\" : code.language;\n const langInfo = getLanguageInfo(cleanLang ?? \"\");\n\n if (\n typeof code.content === \"string\" ||\n typeof code.content === \"number\" ||\n typeof code.content === \"boolean\"\n ) {\n // Apply API key substitution if apiKeys are provided\n let processedContent = String(code.content);\n if (requiresApiKeySubstitution) {\n processedContent = substituteApiKey(\n processedContent,\n selectedApiKey,\n );\n }\n\n if (!langInfo.syntaxHighlighterKey || !cleanLang) return null;\n\n return (\n <Code\n key={code.language}\n language={langInfo.syntaxHighlighterKey || cleanLang}\n snippet={processedContent}\n additionalCSS=\"bg-neutral-100 text-neutral-1300 dark:bg-neutral-1200 dark:text-neutral-200 px-6 py-4\"\n showLines={showCodeLines}\n />\n );\n }\n\n return null;\n });\n }, [\n activeLanguage,\n codeData,\n hasOnlyJsonSnippet,\n showCodeLines,\n apiKeys,\n selectedApiKey,\n ]);\n\n const hasSnippetForActiveLanguage = useMemo(() => {\n if (!activeLanguage) return false;\n if (hasOnlyJsonSnippet) return true;\n\n return codeData.some((code) => {\n return code?.language === activeLanguage;\n });\n }, [activeLanguage, hasOnlyJsonSnippet, codeData]);\n\n const handleSDKTypeChange = useCallback(\n (type: SDKType) => {\n const nextLang = stripSdkType(\n languages.find(\n (l) => l === `${type}_${stripSdkType(activeLanguage)}`,\n ) ??\n languages.find((l) => l.startsWith(`${type}_`)) ??\n activeLanguage,\n );\n\n if (onChange && nextLang) {\n onChange(stripSdkType(activeLanguage), type);\n }\n },\n [languages],\n );\n\n const handleLanguageChange = useCallback(\n (language: string) => {\n if (onChange) {\n onChange(stripSdkType(language), sdk);\n }\n },\n [onChange, sdk],\n );\n\n const NoSnippetMessage = useMemo(() => {\n if (!activeLanguage) return () => null;\n\n const activeLanguageInfo = getLanguageInfo(activeLanguage);\n\n return () => (\n <div className=\"px-16 py-6 ui-text-body2 text-neutral-800 dark:text-neutral-400 text-center flex flex-col gap-3 items-center\">\n <Icon\n name=\"icon-gui-exclamation-triangle-outline\"\n color=\"text-yellow-600 dark:text-yellow-400\"\n size=\"24px\"\n />\n <p className=\"ui-text-p3 text-neutral-700 dark:text-neutral-600\">\n You're currently viewing the {activeLanguageInfo.label} docs.\n There either isn't a {activeLanguageInfo.label} code sample for\n this example, or this feature isn't supported in{\" \"}\n {activeLanguageInfo.label}. Switch language to view this example in a\n different language, or check which SDKs support this feature.\n </p>\n </div>\n );\n }, [activeLanguage]);\n\n const showLanguageSelector = !fixed && filteredLanguages.length > 0;\n const showFullSelector = filteredLanguages.length > 1;\n\n const renderContent = useMemo(() => {\n if (!activeLanguage) return null;\n\n if (hasSnippetForActiveLanguage) {\n return processedChildren;\n }\n\n return <NoSnippetMessage />;\n }, [\n activeLanguage,\n hasSnippetForActiveLanguage,\n processedChildren,\n NoSnippetMessage,\n ]);\n\n // Render special case for plain commands (shell or text)\n if (isSinglePlainCommand) {\n const plainChild = codeData[0];\n if (plainChild) {\n const codeContent = plainChild.content;\n const language = plainChild.language;\n\n if (!language || !codeContent) return null;\n\n // Apply API key substitution if apiKeys are provided\n let processedContent = String(codeContent);\n if (requiresApiKeySubstitution) {\n processedContent = substituteApiKey(processedContent, selectedApiKey);\n }\n\n return (\n <PlainCodeView\n content={processedContent}\n className={className}\n language={language}\n icon={language === \"shell\" ? \"icon-gui-command-line-outline\" : null}\n />\n );\n }\n }\n\n return (\n <div\n className={cn(\n \"rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-1200 border border-neutral-300 dark:border-neutral-1000 min-h-[3.375rem]\",\n className,\n )}\n >\n {headerRow && (\n <div className=\"h-[2.375rem] bg-neutral-200 dark:bg-neutral-1100 border-b border-neutral-300 dark:border-neutral-1000 flex items-center py-1 px-3 rounded-t-lg\">\n <div className=\"flex space-x-1.5\">\n <div className=\"w-3 h-3 rounded-full bg-orange-500\"></div>\n <div className=\"w-3 h-3 rounded-full bg-yellow-500\"></div>\n <div className=\"w-3 h-3 rounded-full bg-green-500\"></div>\n </div>\n\n <div className=\"flex-1 text-center ui-text-p3 font-bold text-neutral-1300 dark:text-neutral-000\">\n {title}\n </div>\n\n {/* Empty div for balance */}\n <div className=\"w-12\"></div>\n </div>\n )}\n {showSDKSelector && (\n <div\n className={cn(\n \"p-2 border-b border-neutral-200 dark:border-neutral-1100 h-14\",\n headerRow ? \"\" : \"rounded-t-lg\",\n )}\n >\n <div className=\"flex gap-3 justify-start\">\n {sdkTypes.has(\"realtime\") && (\n <TooltipButton\n tooltip=\"Realtime SDK\"\n active={sdk === \"realtime\"}\n onClick={() => handleSDKTypeChange(\"realtime\")}\n variant=\"segmented\"\n size=\"sm\"\n alwaysShowLabel={true}\n >\n Realtime\n </TooltipButton>\n )}\n\n {sdkTypes.has(\"rest\") && (\n <TooltipButton\n tooltip=\"REST SDK\"\n active={sdk === \"rest\"}\n onClick={() => handleSDKTypeChange(\"rest\")}\n variant=\"segmented\"\n size=\"sm\"\n alwaysShowLabel={true}\n >\n REST\n </TooltipButton>\n )}\n </div>\n </div>\n )}\n\n {showLanguageSelector &&\n (showFullSelector ? (\n <LanguageSelector\n languages={filteredLanguages}\n activeLanguage={activeLanguage}\n onLanguageChange={handleLanguageChange}\n />\n ) : (\n <div\n className={cn(\n \"border-b border-neutral-200 dark:border-neutral-1100 h-[2.125rem] inline-flex items-center px-3 w-full\",\n { \"rounded-t-lg\": !headerRow },\n )}\n >\n {filteredLanguages.length > 0 && (\n <div\n className={cn(\"inline-flex items-center\", {\n \"cursor-pointer\": filteredLanguages.length > 0,\n })}\n {...(filteredLanguages.length > 0 && {\n onClick: () => handleLanguageChange(filteredLanguages[0]),\n })}\n >\n <Icon\n name={getLanguageInfo(filteredLanguages[0]).icon}\n size=\"16px\"\n additionalCSS=\"mr-2\"\n />\n <span className=\"ui-text-label4 font-semibold text-neutral-800 dark:text-neutral-500 select-none\">\n {getLanguageInfo(filteredLanguages[0]).label}\n </span>\n </div>\n )}\n </div>\n ))}\n <div\n ref={codeRef}\n className=\"relative\"\n onMouseEnter={() => setIsHovering(true)}\n onMouseLeave={() => setIsHovering(false)}\n onFocus={() => setIsHovering(true)}\n onBlur={() => setIsHovering(false)}\n tabIndex={0}\n >\n {renderContent}\n {isHovering && activeLanguage && (\n <CopyButton\n onCopy={() => {\n const text = codeData.find(\n (code) => code.language === activeLanguage,\n )?.content;\n if (text) copy(substituteApiKey(text, selectedApiKey, false));\n }}\n isCopied={isCopied}\n />\n )}\n </div>\n {requiresApiKeySubstitution && (\n <ApiKeySelector\n apiKeys={apiKeys}\n selectedApiKey={selectedApiKey}\n onApiKeyChange={setSelectedApiKey}\n />\n )}\n </div>\n );\n};\n\nexport default CodeSnippet;\n"],"names":["React","useState","useEffect","Children","isValidElement","useRef","useCallback","useMemo","Code","cn","Icon","getLanguageInfo","stripSdkType","LanguageSelector","ApiKeySelector","useCopyToClipboard","PlainCodeView","CopyButton","TooltipButton","substituteApiKey","content","apiKey","mask","replace","split","CodeSnippet","fixed","headerRow","title","children","className","lang","onChange","apiKeys","sdk","showCodeLines","languageOrdering","codeRef","isCopied","copy","selectedApiKey","setSelectedApiKey","keys","key","length","element","current","unmaskRenderedApiKey","handleCopy","event","selection","window","getSelection","rangeCount","selectedText","toString","range","getRangeAt","contains","commonAncestorContainer","modifiedText","clipboardData","setData","preventDefault","document","addEventListener","removeEventListener","extractLanguageFromCode","codeElement","props","classNames","langClass","find","cls","startsWith","substring","codeData","languages","sdkTypes","isSinglePlainCommand","childrenArray","toArray","Set","some","includes","forEach","child","preElement","codeLanguage","add","push","codeContent","language","showSDKSelector","size","filteredLanguages","filtered","filter","sort","a","b","aBase","bBase","aIndex","indexOf","bIndex","activeLanguage","has","requiresApiKeySubstitution","containsPlaceholder","code","isHovering","setIsHovering","hasOnlyJsonSnippet","processedChildren","targetLanguage","map","cleanLang","langInfo","processedContent","String","syntaxHighlighterKey","snippet","additionalCSS","showLines","hasSnippetForActiveLanguage","handleSDKTypeChange","type","nextLang","l","handleLanguageChange","NoSnippetMessage","activeLanguageInfo","div","name","color","p","label","showLanguageSelector","showFullSelector","renderContent","plainChild","icon","tooltip","active","onClick","variant","alwaysShowLabel","onLanguageChange","span","ref","onMouseEnter","onMouseLeave","onFocus","onBlur","tabIndex","onCopy","text","onApiKeyChange"],"mappings":"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"}
|
package/core/Header.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useState,useEffect,useRef,useMemo}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"lodash.throttle";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,isNoticeVisible=false,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[bannerVisible,setBannerVisible]=useState(isNoticeVisible);const menuRef=useRef(null);const[scrollpointClasses,setScrollpointClasses]=useState(themedScrollpoints.length>0?themedScrollpoints[0].className:"");const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};useEffect(()=>{const handleScroll=()=>{setBannerVisible(window.scrollY<=COLLAPSE_TRIGGER_DISTANCE&&isNoticeVisible);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,150);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints]);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",className: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-colors px-6 lg:px-16",scrollpointClasses,{"md:top-auto":bannerVisible}),style:{height:HEADER_HEIGHT}},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
|
|
1
|
+
import React,{useState,useEffect,useRef,useMemo}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"lodash.throttle";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,isNoticeVisible=false,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[bannerVisible,setBannerVisible]=useState(isNoticeVisible);const menuRef=useRef(null);const[scrollpointClasses,setScrollpointClasses]=useState(themedScrollpoints.length>0?themedScrollpoints[0].className:"");const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};useEffect(()=>{const handleScroll=()=>{setBannerVisible(window.scrollY<=COLLAPSE_TRIGGER_DISTANCE&&isNoticeVisible);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,150);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints]);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",className: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-colors px-6 lg:px-16",scrollpointClasses,{"md:top-auto":bannerVisible}),style:{height:HEADER_HEIGHT}},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, { useState, useEffect, useRef, ReactNode, useMemo } 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 \"lodash.throttle\";\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 visible.\n */\n isNoticeVisible?: boolean;\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 isNoticeVisible = false,\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 [bannerVisible, setBannerVisible] = useState(isNoticeVisible);\n const menuRef = useRef<HTMLDivElement>(null);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\n themedScrollpoints.length > 0 ? themedScrollpoints[0].className : \"\",\n );\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n useEffect(() => {\n const handleScroll = () => {\n setBannerVisible(\n window.scrollY <= COLLAPSE_TRIGGER_DISTANCE && isNoticeVisible,\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, 150);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints]);\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]);\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\n role=\"banner\"\n className={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-colors px-6 lg:px-16\",\n scrollpointClasses,\n {\n \"md:top-auto\": bannerVisible,\n },\n )}\n style={{ height: HEADER_HEIGHT }}\n >\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(\n \"h-full focus-base rounded mr-4 lg:mr-8 gap-2 items-center\",\n {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n },\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","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","COLLAPSE_TRIGGER_DISTANCE","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","className","isNoticeVisible","searchBar","searchButton","logoHref","headerLinks","headerLinksClassName","headerCenterClassName","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","location","logoBadge","showMenu","setShowMenu","fadingOut","setFadingOut","bannerVisible","setBannerVisible","menuRef","scrollpointClasses","setScrollpointClasses","length","closeMenu","setTimeout","handleScroll","window","scrollY","scrollpoint","element","document","getElementById","id","rect","getBoundingClientRect","top","bottom","throttledHandleScroll","addEventListener","removeEventListener","handleResize","innerWidth","body","classList","add","remove","wrappedSearchButton","div","header","role","style","height","map","theme","key","href","badge","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxWidth","maxHeight","ref"],"mappings":"AAAA,OAAOA,OAASC,QAAQ,CAAEC,SAAS,CAAEC,MAAM,CAAaC,OAAO,KAAQ,OAAQ,AAC/E,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,YAAa,AAC5B,QAAOC,SAAU,QAAS,AAC1B,QACEC,kBAAkB,CAClBC,oBAAoB,CACpBC,aAAa,KACR,iBAAkB,AACzB,QAASC,WAAW,KAAQ,sBAAuB,AACnD,QAAOC,aAAc,iBAAkB,AAEvC,QAASC,yBAAyB,KAAQ,oBAAqB,CAqI/D,MAAMC,yBAA2B,4CAKjC,MAAMC,sBAAwB,QAE9B,MAAMC,OAAgC,CAAC,CACrCC,SAAS,CACTC,gBAAkB,KAAK,CACvBC,SAAS,CACTC,YAAY,CACZC,QAAQ,CACRC,WAAW,CACXC,oBAAoB,CACpBC,qBAAqB,CACrBC,GAAG,CACHC,SAAS,CACTC,YAAY,CACZC,mBAAqB,EAAE,CACvBC,uBAAyB,KAAK,CAC9BC,QAAQ,CACRC,SAAS,CACV,IACC,KAAM,CAACC,SAAUC,YAAY,CAAGhC,SAAS,OACzC,KAAM,CAACiC,UAAWC,aAAa,CAAGlC,SAAS,OAC3C,KAAM,CAACmC,cAAeC,iBAAiB,CAAGpC,SAASiB,iBACnD,MAAMoB,QAAUnC,OAAuB,MACvC,KAAM,CAACoC,mBAAoBC,sBAAsB,CAAGvC,SAClD2B,mBAAmBa,MAAM,CAAG,EAAIb,kBAAkB,CAAC,EAAE,CAACX,SAAS,CAAG,IAGpE,MAAMyB,UAAY,KAChBP,aAAa,MAEbQ,WAAW,KACTV,YAAY,OACZE,aAAa,MACf,EAAG,IACL,EAEAjC,UAAU,KACR,MAAM0C,aAAe,KACnBP,iBACEQ,OAAOC,OAAO,EAAIjC,2BAA6BK,iBAEjD,IAAK,MAAM6B,eAAenB,mBAAoB,CAC5C,MAAMoB,QAAUC,SAASC,cAAc,CAACH,YAAYI,EAAE,EACtD,GAAIH,QAAS,CACX,MAAMI,KAAOJ,QAAQK,qBAAqB,GAC1C,GAAID,KAAKE,GAAG,EAAI5C,eAAiB0C,KAAKG,MAAM,EAAI7C,cAAe,CAC7D8B,sBAAsBO,YAAY9B,SAAS,EAC3C,MACF,CACF,CACF,CACF,EAEA,MAAMuC,sBAAwB5C,SAASgC,aAAc,KAErDA,eAEAC,OAAOY,gBAAgB,CAAC,SAAUD,uBAClC,MAAO,IAAMX,OAAOa,mBAAmB,CAAC,SAAUF,sBACpD,EAAG,CAAC5B,mBAAmB,EAEvB1B,UAAU,KACR,MAAMyD,aAAe,KACnB,GAAId,OAAOe,UAAU,EAAI,KAAM,CAC7B3B,YAAY,MACd,CACF,EACAY,OAAOY,gBAAgB,CAAC,SAAUE,cAClC,MAAO,IAAMd,OAAOa,mBAAmB,CAAC,SAAUC,aACpD,EAAG,EAAE,EAELzD,UAAU,KACR,GAAI8B,SAAU,CACZiB,SAASY,IAAI,CAACC,SAAS,CAACC,GAAG,CAAC,kBAC9B,KAAO,CACLd,SAASY,IAAI,CAACC,SAAS,CAACE,MAAM,CAAC,kBACjC,CAGA,MAAO,KACLf,SAASY,IAAI,CAACC,SAAS,CAACE,MAAM,CAAC,kBACjC,CACF,EAAG,CAAChC,SAAS,EAGb9B,UAAU,KACR,GAAI4B,UAAYE,SAAU,CACxBU,WACF,CACF,EAAG,CAACZ,SAAS,EAEb,MAAMmC,oBAAsB7D,QAC1B,IACEgB,aACE,oBAAC8C,OAAIjD,UAAU,6DACZG,cAED,KACN,CAACA,aAAa,EAGhB,OACE,wCACE,oBAAC+C,UACCC,KAAK,SACLnD,UAAWX,GACT,0JACAiC,mBACA,CACE,cAAeH,aACjB,GAEFiC,MAAO,CAAEC,OAAQ5D,aAAc,GAE/B,oBAACwD,OAAIjD,UAAWX,GAAG,2BAA4BW,YAC7C,oBAACQ,OAAIR,UAAU,mCACZ,AAAC,CAAC,QAAS,OAAO,CAAasD,GAAG,CAAC,AAACC,OACnC,oBAACjE,MACCkE,IAAKD,MACLE,KAAMrD,SACNmD,MAAOA,MACPG,MAAO5C,UACP6C,oBAAqB,CACnB3D,UAAWX,GACT,4DACA,CACE,mBAAoBkE,QAAU,QAC9B,mBAAoBA,QAAU,MAChC,EAEJ,KAGJ,oBAACN,OAAIjD,UAAWH,0BAA2BW,MAE7C,oBAACyC,OAAIjD,UAAU,+DACZY,yBAA2B,UAAYoC,oBAAsB,KAC9D,oBAACY,UACC5D,UAAU,0DACV6D,QAAS,IAAM7C,YAAY,CAACD,UAC5B+C,gBAAe/C,SACfgD,gBAAc,cACdC,aAAW,eAEX,oBAAC5E,MACC6E,KACElD,SACI,0BACA,0BAENmD,cAAc,0CACdC,KAAK,aAIVjE,UACC,oBAAC+C,OACCjD,UAAWX,GACTQ,yBACA,iBACAU,wBAGDL,WAED,KACJ,oBAACR,aACCM,UAAWX,GAAGQ,yBAA0BS,sBACxCD,YAAaA,YACbK,aAAcA,aACdP,aAAc6C,oBACdpC,uBAAwBA,2BAI7BG,SACC,wCACE,oBAACkC,OACCjD,UAAWX,GACT,0DACA,CACE,2DACE,CAAC4B,UACH,4DACEA,SACJ,GAEF4C,QAASpC,UACT2C,UAAW,AAACC,GAAMA,EAAEb,GAAG,GAAK,UAAY/B,YACxC0B,KAAK,iBAEP,oBAACF,OACCf,GAAG,cACHlC,UAAU,0KACVoD,MAAO,CACLkB,SAAUxE,sBACVyE,UAAWhF,mBACTE,cACAD,qBAEJ,EACAgF,IAAKnD,QACL8B,KAAK,cAEJ1C,UACD,oBAACf,aACCW,YAAaA,YACbK,aAAcA,iBAIlB,KAGV,CAEA,gBAAeX,MAAO"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/Header.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, ReactNode, useMemo } 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 \"lodash.throttle\";\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 visible.\n */\n isNoticeVisible?: boolean;\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 isNoticeVisible = false,\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 [bannerVisible, setBannerVisible] = useState(isNoticeVisible);\n const menuRef = useRef<HTMLDivElement>(null);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\n themedScrollpoints.length > 0 ? themedScrollpoints[0].className : \"\",\n );\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n useEffect(() => {\n const handleScroll = () => {\n setBannerVisible(\n window.scrollY <= COLLAPSE_TRIGGER_DISTANCE && isNoticeVisible,\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, 150);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints]);\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]);\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\n role=\"banner\"\n className={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-colors px-6 lg:px-16\",\n scrollpointClasses,\n {\n \"md:top-auto\": bannerVisible,\n },\n )}\n style={{ height: HEADER_HEIGHT }}\n >\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","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","COLLAPSE_TRIGGER_DISTANCE","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","className","isNoticeVisible","searchBar","searchButton","logoHref","headerLinks","headerLinksClassName","headerCenterClassName","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","location","logoBadge","showMenu","setShowMenu","fadingOut","setFadingOut","bannerVisible","setBannerVisible","menuRef","scrollpointClasses","setScrollpointClasses","length","closeMenu","setTimeout","handleScroll","window","scrollY","scrollpoint","element","document","getElementById","id","rect","getBoundingClientRect","top","bottom","throttledHandleScroll","addEventListener","removeEventListener","handleResize","innerWidth","body","classList","add","remove","wrappedSearchButton","div","header","role","style","height","map","theme","key","href","badge","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxWidth","maxHeight","ref"],"mappings":"AAAA,OAAOA,OAASC,QAAQ,CAAEC,SAAS,CAAEC,MAAM,CAAaC,OAAO,KAAQ,OAAQ,AAC/E,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,YAAa,AAC5B,QAAOC,SAAU,QAAS,AAC1B,QACEC,kBAAkB,CAClBC,oBAAoB,CACpBC,aAAa,KACR,iBAAkB,AACzB,QAASC,WAAW,KAAQ,sBAAuB,AACnD,QAAOC,aAAc,iBAAkB,AAEvC,QAASC,yBAAyB,KAAQ,oBAAqB,CAqI/D,MAAMC,yBAA2B,4CAKjC,MAAMC,sBAAwB,QAE9B,MAAMC,OAAgC,CAAC,CACrCC,SAAS,CACTC,gBAAkB,KAAK,CACvBC,SAAS,CACTC,YAAY,CACZC,QAAQ,CACRC,WAAW,CACXC,oBAAoB,CACpBC,qBAAqB,CACrBC,GAAG,CACHC,SAAS,CACTC,YAAY,CACZC,mBAAqB,EAAE,CACvBC,uBAAyB,KAAK,CAC9BC,QAAQ,CACRC,SAAS,CACV,IACC,KAAM,CAACC,SAAUC,YAAY,CAAGhC,SAAS,OACzC,KAAM,CAACiC,UAAWC,aAAa,CAAGlC,SAAS,OAC3C,KAAM,CAACmC,cAAeC,iBAAiB,CAAGpC,SAASiB,iBACnD,MAAMoB,QAAUnC,OAAuB,MACvC,KAAM,CAACoC,mBAAoBC,sBAAsB,CAAGvC,SAClD2B,mBAAmBa,MAAM,CAAG,EAAIb,kBAAkB,CAAC,EAAE,CAACX,SAAS,CAAG,IAGpE,MAAMyB,UAAY,KAChBP,aAAa,MAEbQ,WAAW,KACTV,YAAY,OACZE,aAAa,MACf,EAAG,IACL,EAEAjC,UAAU,KACR,MAAM0C,aAAe,KACnBP,iBACEQ,OAAOC,OAAO,EAAIjC,2BAA6BK,iBAEjD,IAAK,MAAM6B,eAAenB,mBAAoB,CAC5C,MAAMoB,QAAUC,SAASC,cAAc,CAACH,YAAYI,EAAE,EACtD,GAAIH,QAAS,CACX,MAAMI,KAAOJ,QAAQK,qBAAqB,GAC1C,GAAID,KAAKE,GAAG,EAAI5C,eAAiB0C,KAAKG,MAAM,EAAI7C,cAAe,CAC7D8B,sBAAsBO,YAAY9B,SAAS,EAC3C,MACF,CACF,CACF,CACF,EAEA,MAAMuC,sBAAwB5C,SAASgC,aAAc,KAErDA,eAEAC,OAAOY,gBAAgB,CAAC,SAAUD,uBAClC,MAAO,IAAMX,OAAOa,mBAAmB,CAAC,SAAUF,sBACpD,EAAG,CAAC5B,mBAAmB,EAEvB1B,UAAU,KACR,MAAMyD,aAAe,KACnB,GAAId,OAAOe,UAAU,EAAI,KAAM,CAC7B3B,YAAY,MACd,CACF,EACAY,OAAOY,gBAAgB,CAAC,SAAUE,cAClC,MAAO,IAAMd,OAAOa,mBAAmB,CAAC,SAAUC,aACpD,EAAG,EAAE,EAELzD,UAAU,KACR,GAAI8B,SAAU,CACZiB,SAASY,IAAI,CAACC,SAAS,CAACC,GAAG,CAAC,kBAC9B,KAAO,CACLd,SAASY,IAAI,CAACC,SAAS,CAACE,MAAM,CAAC,kBACjC,CAGA,MAAO,KACLf,SAASY,IAAI,CAACC,SAAS,CAACE,MAAM,CAAC,kBACjC,CACF,EAAG,CAAChC,SAAS,EAGb9B,UAAU,KACR,GAAI4B,UAAYE,SAAU,CACxBU,WACF,CACF,EAAG,CAACZ,SAAS,EAEb,MAAMmC,oBAAsB7D,QAC1B,IACEgB,aACE,oBAAC8C,OAAIjD,UAAU,6DACZG,cAED,KACN,CAACA,aAAa,EAGhB,OACE,wCACE,oBAAC+C,UACCC,KAAK,SACLnD,UAAWX,GACT,0JACAiC,mBACA,CACE,cAAeH,aACjB,GAEFiC,MAAO,CAAEC,OAAQ5D,aAAc,GAE/B,oBAACwD,OAAIjD,UAAWX,GAAG,2BAA4BW,YAC7C,oBAACQ,OAAIR,UAAU,mCACZ,AAAC,CAAC,QAAS,OAAO,CAAasD,GAAG,CAAC,AAACC,OACnC,oBAACjE,MACCkE,IAAKD,MACLE,KAAMrD,SACNmD,MAAOA,MACPG,MAAO5C,UACP6C,oBAAqB,CACnB3D,UAAWX,GAAG,yCAA0C,CACtD,mBAAoBkE,QAAU,QAC9B,mBAAoBA,QAAU,MAChC,EACF,KAGJ,oBAACN,OAAIjD,UAAWH,0BAA2BW,MAE7C,oBAACyC,OAAIjD,UAAU,+DACZY,yBAA2B,UAAYoC,oBAAsB,KAC9D,oBAACY,UACC5D,UAAU,0DACV6D,QAAS,IAAM7C,YAAY,CAACD,UAC5B+C,gBAAe/C,SACfgD,gBAAc,cACdC,aAAW,eAEX,oBAAC5E,MACC6E,KACElD,SACI,0BACA,0BAENmD,cAAc,0CACdC,KAAK,aAIVjE,UACC,oBAAC+C,OACCjD,UAAWX,GACTQ,yBACA,iBACAU,wBAGDL,WAED,KACJ,oBAACR,aACCM,UAAWX,GAAGQ,yBAA0BS,sBACxCD,YAAaA,YACbK,aAAcA,aACdP,aAAc6C,oBACdpC,uBAAwBA,2BAI7BG,SACC,wCACE,oBAACkC,OACCjD,UAAWX,GACT,0DACA,CACE,2DACE,CAAC4B,UACH,4DACEA,SACJ,GAEF4C,QAASpC,UACT2C,UAAW,AAACC,GAAMA,EAAEb,GAAG,GAAK,UAAY/B,YACxC0B,KAAK,iBAEP,oBAACF,OACCf,GAAG,cACHlC,UAAU,0KACVoD,MAAO,CACLkB,SAAUxE,sBACVyE,UAAWhF,mBACTE,cACAD,qBAEJ,EACAgF,IAAKnD,QACL8B,KAAK,cAEJ1C,UACD,oBAACf,aACCW,YAAaA,YACbK,aAAcA,iBAIlB,KAGV,CAEA,gBAAeX,MAAO"}
|
package/core/Logo.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Logo.tsx"],"sourcesContent":["import React, {
|
|
1
|
+
{"version":3,"sources":["../../src/core/Logo.tsx"],"sourcesContent":["import React, { AnchorHTMLAttributes, ImgHTMLAttributes } from \"react\";\nimport Badge from \"./Badge\";\nimport cn from \"./utils/cn\";\nimport LogoAssetMonoStacked from \"./images/logo/ably-logo-mono-stacked.svg\";\nimport LogoAssetMonoWhiteStacked from \"./images/logo/ably-logo-mono-white-stacked.svg\";\nimport LogoAssetMonoWhite from \"./images/logo/ably-logo-mono-white.svg\";\nimport LogoAssetMono from \"./images/logo/ably-logo-mono.svg\";\nimport LogoAssetStacked from \"./images/logo/ably-logo-stacked.svg\";\nimport LogoAssetWhiteStacked from \"./images/logo/ably-logo-white-stacked.svg\";\nimport LogoAssetWhite from \"./images/logo/ably-logo-white.svg\";\nimport LogoAsset from \"./images/logo/ably-logo.svg\";\n\ntype LogoProps = {\n dataId?: string;\n logoUrl?: string;\n logoAlt?: string;\n href?: string;\n additionalImgAttrs?: ImgHTMLAttributes<HTMLImageElement>;\n additionalLinkAttrs?: AnchorHTMLAttributes<HTMLAnchorElement>;\n theme?: \"light\" | \"dark\";\n variant?: \"default\" | \"mono\";\n orientation?: \"default\" | \"stacked\";\n badge?: string;\n};\n\nconst Logo = ({\n dataId,\n href = \"/\",\n additionalImgAttrs,\n additionalLinkAttrs,\n theme = \"light\",\n variant = \"default\",\n orientation = \"default\",\n logoUrl,\n logoAlt = \"Ably logo\",\n badge,\n}: LogoProps) => {\n const getLogoSrc = React.useCallback(() => {\n if (logoUrl) return logoUrl;\n\n if (theme === \"dark\") {\n if (variant === \"mono\") {\n return orientation === \"stacked\"\n ? LogoAssetMonoWhiteStacked\n : LogoAssetMonoWhite;\n } else {\n return orientation === \"stacked\"\n ? LogoAssetWhiteStacked\n : LogoAssetWhite;\n }\n } else {\n if (variant === \"mono\") {\n return orientation === \"stacked\" ? LogoAssetMonoStacked : LogoAssetMono;\n } else {\n return orientation === \"stacked\" ? LogoAssetStacked : LogoAsset;\n }\n }\n }, [logoUrl, theme, variant, orientation]);\n\n const logoSrc = getLogoSrc();\n\n return (\n <a\n href={href}\n data-id={dataId}\n {...additionalLinkAttrs}\n className={cn(\n \"flex items-center gap-2 justify-center\",\n additionalLinkAttrs?.className,\n )}\n >\n <img src={logoSrc} width=\"96px\" alt={logoAlt} {...additionalImgAttrs} />\n {badge && (\n <Badge className=\"uppercase h-8 bg-transparent dark:bg-transparent rounded border border-neutral-400 dark:border-neutral-900 text-lg p-2 font-semibold text-neutral-800 dark:text-neutral-500\">\n {badge}\n </Badge>\n )}\n </a>\n );\n};\n\nexport default React.memo(Logo);\n"],"names":["React","Badge","cn","LogoAssetMonoStacked","LogoAssetMonoWhiteStacked","LogoAssetMonoWhite","LogoAssetMono","LogoAssetStacked","LogoAssetWhiteStacked","LogoAssetWhite","LogoAsset","Logo","dataId","href","additionalImgAttrs","additionalLinkAttrs","theme","variant","orientation","logoUrl","logoAlt","badge","getLogoSrc","useCallback","logoSrc","a","data-id","className","img","src","width","alt","memo"],"mappings":"AAAA,OAAOA,UAAwD,OAAQ,AACvE,QAAOC,UAAW,SAAU,AAC5B,QAAOC,OAAQ,YAAa,AAC5B,QAAOC,yBAA0B,0CAA2C,AAC5E,QAAOC,8BAA+B,gDAAiD,AACvF,QAAOC,uBAAwB,wCAAyC,AACxE,QAAOC,kBAAmB,kCAAmC,AAC7D,QAAOC,qBAAsB,qCAAsC,AACnE,QAAOC,0BAA2B,2CAA4C,AAC9E,QAAOC,mBAAoB,mCAAoC,AAC/D,QAAOC,cAAe,6BAA8B,CAepD,MAAMC,KAAO,CAAC,CACZC,MAAM,CACNC,KAAO,GAAG,CACVC,kBAAkB,CAClBC,mBAAmB,CACnBC,MAAQ,OAAO,CACfC,QAAU,SAAS,CACnBC,YAAc,SAAS,CACvBC,OAAO,CACPC,QAAU,WAAW,CACrBC,KAAK,CACK,IACV,MAAMC,WAAatB,MAAMuB,WAAW,CAAC,KACnC,GAAIJ,QAAS,OAAOA,QAEpB,GAAIH,QAAU,OAAQ,CACpB,GAAIC,UAAY,OAAQ,CACtB,OAAOC,cAAgB,UACnBd,0BACAC,kBACN,KAAO,CACL,OAAOa,cAAgB,UACnBV,sBACAC,cACN,CACF,KAAO,CACL,GAAIQ,UAAY,OAAQ,CACtB,OAAOC,cAAgB,UAAYf,qBAAuBG,aAC5D,KAAO,CACL,OAAOY,cAAgB,UAAYX,iBAAmBG,SACxD,CACF,CACF,EAAG,CAACS,QAASH,MAAOC,QAASC,YAAY,EAEzC,MAAMM,QAAUF,aAEhB,OACE,oBAACG,KACCZ,KAAMA,KACNa,UAASd,OACR,GAAGG,mBAAmB,CACvBY,UAAWzB,GACT,yCACAa,qBAAqBY,YAGvB,oBAACC,OAAIC,IAAKL,QAASM,MAAM,OAAOC,IAAKX,QAAU,GAAGN,kBAAkB,GACnEO,OACC,oBAACpB,OAAM0B,UAAU,+KACdN,OAKX,CAEA,gBAAerB,MAAMgC,IAAI,CAACrB,KAAM"}
|
package/index.d.ts
CHANGED
|
@@ -5196,14 +5196,14 @@ export default Loader;
|
|
|
5196
5196
|
}
|
|
5197
5197
|
|
|
5198
5198
|
declare module '@ably/ui/core/Logo' {
|
|
5199
|
-
import React, {
|
|
5199
|
+
import React, { AnchorHTMLAttributes, ImgHTMLAttributes } from "react";
|
|
5200
5200
|
type LogoProps = {
|
|
5201
5201
|
dataId?: string;
|
|
5202
5202
|
logoUrl?: string;
|
|
5203
5203
|
logoAlt?: string;
|
|
5204
5204
|
href?: string;
|
|
5205
|
-
additionalImgAttrs?:
|
|
5206
|
-
additionalLinkAttrs?:
|
|
5205
|
+
additionalImgAttrs?: ImgHTMLAttributes<HTMLImageElement>;
|
|
5206
|
+
additionalLinkAttrs?: AnchorHTMLAttributes<HTMLAnchorElement>;
|
|
5207
5207
|
theme?: "light" | "dark";
|
|
5208
5208
|
variant?: "default" | "mono";
|
|
5209
5209
|
orientation?: "default" | "stacked";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ably/ui",
|
|
3
|
-
"version": "17.6.
|
|
3
|
+
"version": "17.6.3",
|
|
4
4
|
"description": "Home of the Ably design system library ([design.ably.com](https://design.ably.com)). It provides a showcase, development/test environment and a publishing pipeline for different distributables.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"workerDirectory": "./public"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@storybook/addon-docs": "^9.
|
|
23
|
-
"@storybook/react-vite": "^9.
|
|
22
|
+
"@storybook/addon-docs": "^9.1.1",
|
|
23
|
+
"@storybook/react-vite": "^9.1.1",
|
|
24
24
|
"@storybook/test-runner": "^0.23.0",
|
|
25
25
|
"@svgr/core": "^8.1.0",
|
|
26
26
|
"@svgr/plugin-jsx": "^8.1.0",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"eslint": "^8.57.0",
|
|
43
43
|
"eslint-config-prettier": "^10.0.1",
|
|
44
44
|
"eslint-plugin-react": "^7.34.3",
|
|
45
|
-
"eslint-plugin-storybook": "^9.
|
|
45
|
+
"eslint-plugin-storybook": "^9.1.1",
|
|
46
46
|
"heroicons": "^2.2.0",
|
|
47
47
|
"http-server": "14.1.1",
|
|
48
48
|
"jsdom": "^26.0.0",
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
"playwright": "^1.49.1",
|
|
53
53
|
"posthog-js": "^1.217.4",
|
|
54
54
|
"prettier": "^3.2.5",
|
|
55
|
-
"storybook": "^9.
|
|
55
|
+
"storybook": "^9.1.1",
|
|
56
56
|
"svg-sprite": "^2.0.4",
|
|
57
57
|
"tailwindcss": "^3.3.6",
|
|
58
58
|
"ts-node": "^10.9.2",
|
|
59
59
|
"typescript": "5.8.3",
|
|
60
|
-
"vite": "^
|
|
60
|
+
"vite": "^7.1.1",
|
|
61
61
|
"vitest": "^3.0.8",
|
|
62
62
|
"@vueless/storybook-dark-mode": "^9.0.6",
|
|
63
63
|
"wait-on": "^8.0.3"
|