@ably/ui 17.13.1 → 17.14.0-dev.1101c91c8f
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/AGENTS.md +8 -13
- package/README.md +16 -0
- package/core/Code.js +1 -1
- package/core/Code.js.map +1 -1
- package/core/CodeSnippet.js +1 -1
- package/core/CodeSnippet.js.map +1 -1
- package/core/Meganav/data.js +1 -1
- package/core/Meganav/data.js.map +1 -1
- package/core/utils/syntax-highlighter.css +25 -0
- package/core/utils/syntax-highlighter.js +1 -1
- package/core/utils/syntax-highlighter.js.map +1 -1
- package/index.d.ts +32 -1
- package/package.json +6 -6
package/AGENTS.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This file is not necessarily for people, the intended audience is automated agents.
|
|
4
4
|
|
|
5
|
+
> This file contains @ably/ui package-specific guidance. For universal code style and git workflow, see the [root AGENTS.md](../../AGENTS.md).
|
|
6
|
+
|
|
5
7
|
## Other references
|
|
6
8
|
|
|
7
9
|
Consider the content of `README.md` as well, it contains technical information
|
|
@@ -25,14 +27,12 @@ This project is intended to primarily be consumed by the Ably website, voltaire
|
|
|
25
27
|
|
|
26
28
|
## Code Style
|
|
27
29
|
|
|
28
|
-
- **Language**: TypeScript with strict mode enabled
|
|
29
30
|
- **React**: Use functional components with hooks; React 18.x
|
|
30
31
|
- **Imports**: Default export for main component, named exports for types/utils
|
|
31
32
|
- **Naming**: PascalCase for components/types, camelCase for functions/variables,
|
|
32
33
|
kebab-case for files
|
|
33
34
|
- **Types**: Define prop types as `ComponentNameProps`, use `PropsWithChildren<T>`
|
|
34
35
|
when needed
|
|
35
|
-
- **Styling**: Tailwind 3.4.
|
|
36
36
|
- **Utility**: Use `cn()` from `./src/core/utils/cn` for className merging (clsx
|
|
37
37
|
& tailwind-merge)
|
|
38
38
|
- **Formatting**: Prettier defaults (no config = defaults), 2-space indent
|
|
@@ -67,12 +67,6 @@ export function useContentHeight(
|
|
|
67
67
|
}
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Keep emojis in the code to a minimum, only introduce them if there is precedent
|
|
71
|
-
in the file you're working on.
|
|
72
|
-
|
|
73
|
-
Comments and commit messages should not include statements like "local tests pass",
|
|
74
|
-
this is a given for how we work.
|
|
75
|
-
|
|
76
70
|
## Development
|
|
77
71
|
|
|
78
72
|
- Run `pnpm lint` & `pnpm format:write` on files after making changes, we lint
|
|
@@ -527,8 +521,9 @@ This allows testing tiebreaker logic and initial state detection. Storybook stor
|
|
|
527
521
|
|
|
528
522
|
## Git workflow
|
|
529
523
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
-
|
|
524
|
+
See the [root AGENTS.md](../../AGENTS.md) for universal git workflow guidance.
|
|
525
|
+
|
|
526
|
+
**UI package-specific notes:**
|
|
527
|
+
|
|
528
|
+
- Run `pnpm lint` and `pnpm test` before pushing
|
|
529
|
+
- For performance-related changes, compare before/after metrics and include in commit/PR
|
package/README.md
CHANGED
|
@@ -358,6 +358,22 @@ This will trigger GitHub actions in supported apps (currently [Voltaire](http://
|
|
|
358
358
|
|
|
359
359
|
This will release the packages and update library and create & push the commit & tag, and also create corresponding PRs in Voltaire & Website. It will also deploy a new Storybook site to [https://ably.github.io/ably-ui/](https://ably.github.io/ably-ui/).
|
|
360
360
|
|
|
361
|
+
### Tagging Convention (Monorepo)
|
|
362
|
+
|
|
363
|
+
In the monorepo, ably-ui uses **component-prefixed tags** to enable independent releases:
|
|
364
|
+
|
|
365
|
+
**Release tags:** `ui-<version>` (e.g., `ui-17.13.2`)
|
|
366
|
+
- Used for production NPM releases
|
|
367
|
+
- Created via GitHub Releases
|
|
368
|
+
- Do NOT include `v` prefix
|
|
369
|
+
|
|
370
|
+
**Pre-release tags:** `ui-v<version>-dev.<sha>` (e.g., `ui-v17.13.2-dev.a1b2c3d`)
|
|
371
|
+
- Created automatically by `./scripts/pre-release.sh`
|
|
372
|
+
- Published to NPM with `dev` tag
|
|
373
|
+
- Includes `v` prefix and commit SHA
|
|
374
|
+
|
|
375
|
+
See the [root docs/TAGGING.md](../../docs/TAGGING.md) for complete details on the monorepo tagging convention.
|
|
376
|
+
|
|
361
377
|
### Review Apps
|
|
362
378
|
|
|
363
379
|
Review apps allow you to create temporary deployments of Storybook for sharing UI changes with stakeholders without requiring local development setup.
|
package/core/Code.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React from"react";import{highlightSnippet,registerDefaultLanguages}from"./utils/syntax-highlighter";import languagesRegistry from"./utils/syntax-highlighter-registry";import cn from"./utils/cn";registerDefaultLanguages(languagesRegistry);const Code=({language,snippet,textSize="ui-text-code",padding="p-8",additionalCSS="",showLines,lineCSS,wrap=false})=>{const trimmedSnippet=snippet.trimEnd();const HTMLraw=highlightSnippet(language,trimmedSnippet)??"";const className=`language-${language} ${textSize}`;const lines=trimmedSnippet.split(/\r\n|\r|\n/);const lineCount=lines.length;return React.createElement("div",{className:cn("hljs overflow-y-auto flex",padding,additionalCSS),"data-id":"code"},showLines?React.createElement("div",{className:"text-p4 leading-normal pt-px"},[...Array(lineCount)].map((_,i)=>React.createElement("p",{className:cn("mr-4 font-mono text-right text-neutral-800",lineCSS),key:i},i+1))):null,React.createElement("pre",{lang:language,className:cn("h-full flex-1 text-p4 leading-normal",wrap?"whitespace-pre-wrap break-words":"overflow-x-auto")},React.createElement("code",{className:className,dangerouslySetInnerHTML:{__html:HTMLraw}})))};export default Code;
|
|
1
|
+
import React from"react";import{highlightSnippet,registerDefaultLanguages,splitHtmlLines}from"./utils/syntax-highlighter";import languagesRegistry from"./utils/syntax-highlighter-registry";import cn from"./utils/cn";registerDefaultLanguages(languagesRegistry);const LINE_HIGHLIGHT_CLASSES={addition:"code-line-addition",removal:"code-line-removal",highlight:"code-line-highlight"};const Code=({language,snippet,textSize="ui-text-code",padding="p-8",additionalCSS="",showLines,lineCSS,wrap=false,lineHighlights})=>{const trimmedSnippet=snippet.trimEnd();const HTMLraw=highlightSnippet(language,trimmedSnippet)??"";const className=`language-${language} ${textSize}`;const lines=trimmedSnippet.split(/\r\n|\r|\n/);const lineCount=lines.length;const hasHighlights=lineHighlights&&Object.keys(lineHighlights).length>0;if(hasHighlights){const htmlLines=splitHtmlLines(HTMLraw);return React.createElement("div",{className:cn("hljs overflow-y-auto",padding,additionalCSS),"data-id":"code"},React.createElement("pre",{lang:language,className:cn("h-full flex-1 text-p4 leading-normal",wrap?"whitespace-pre-wrap break-words":"overflow-x-auto")},htmlLines.map((lineHtml,i)=>{const lineNum=i+1;const highlightType=lineHighlights[lineNum];const highlightClass=highlightType?LINE_HIGHLIGHT_CLASSES[highlightType]:undefined;return React.createElement("div",{key:i,className:cn("flex min-w-full",highlightClass)},showLines&&React.createElement("span",{className:cn("mr-4 font-mono text-right text-neutral-800 select-none shrink-0 inline-block",lineCSS),style:{minWidth:`${String(lineCount).length}ch`}},lineNum),React.createElement("code",{className:cn(className,"flex-1 !leading-normal"),dangerouslySetInnerHTML:{__html:lineHtml||" "}}))})))}return React.createElement("div",{className:cn("hljs overflow-y-auto flex",padding,additionalCSS),"data-id":"code"},showLines?React.createElement("div",{className:"text-p4 leading-normal pt-px"},[...Array(lineCount)].map((_,i)=>React.createElement("p",{className:cn("mr-4 font-mono text-right text-neutral-800",lineCSS),key:i},i+1))):null,React.createElement("pre",{lang:language,className:cn("h-full flex-1 text-p4 leading-normal",wrap?"whitespace-pre-wrap break-words":"overflow-x-auto")},React.createElement("code",{className:className,dangerouslySetInnerHTML:{__html:HTMLraw}})))};export default Code;
|
|
2
2
|
//# sourceMappingURL=Code.js.map
|
package/core/Code.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Code.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n highlightSnippet,\n registerDefaultLanguages,\n} from \"./utils/syntax-highlighter\";\nimport languagesRegistry from \"./utils/syntax-highlighter-registry\";\nimport cn from \"./utils/cn\";\n\nregisterDefaultLanguages(languagesRegistry);\n\ntype CodeProps = {\n language: string;\n snippet: string;\n textSize?: string;\n padding?: string;\n additionalCSS?: string;\n showLines?: boolean;\n lineCSS?: string;\n wrap?: boolean;\n};\n\nconst Code = ({\n language,\n snippet,\n textSize = \"ui-text-code\",\n padding = \"p-8\",\n additionalCSS = \"\",\n showLines,\n lineCSS,\n wrap = false,\n}: CodeProps) => {\n // Trim the snippet and remove trailing empty lines\n const trimmedSnippet = snippet.trimEnd();\n const HTMLraw = highlightSnippet(language, trimmedSnippet) ?? \"\";\n const className = `language-${language} ${textSize}`;\n\n // Calculate line count after removing trailing empty lines\n const lines = trimmedSnippet.split(/\\r\\n|\\r|\\n/);\n const lineCount = lines.length;\n\n return (\n <div\n className={cn(\"hljs overflow-y-auto flex\", padding, additionalCSS)}\n data-id=\"code\"\n >\n {showLines ? (\n <div className=\"text-p4 leading-normal pt-px\">\n {[...Array(lineCount)].map((_, i) => (\n <p\n className={cn(\n \"mr-4 font-mono text-right text-neutral-800\",\n lineCSS,\n )}\n key={i}\n >\n {i + 1}\n </p>\n ))}\n </div>\n ) : null}\n <pre\n lang={language}\n className={cn(\n \"h-full flex-1 text-p4 leading-normal\",\n wrap ? \"whitespace-pre-wrap break-words\" : \"overflow-x-auto\",\n )}\n >\n <code\n className={className}\n dangerouslySetInnerHTML={{ __html: HTMLraw }}\n />\n </pre>\n </div>\n );\n};\n\nexport default Code;\n"],"names":["React","highlightSnippet","registerDefaultLanguages","languagesRegistry","cn","Code","language","snippet","textSize","padding","additionalCSS","showLines","lineCSS","wrap","trimmedSnippet","trimEnd","HTMLraw","className","lines","split","lineCount","length","div","data-id","
|
|
1
|
+
{"version":3,"sources":["../../src/core/Code.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n highlightSnippet,\n registerDefaultLanguages,\n splitHtmlLines,\n} from \"./utils/syntax-highlighter\";\nimport languagesRegistry from \"./utils/syntax-highlighter-registry\";\nimport cn from \"./utils/cn\";\n\nregisterDefaultLanguages(languagesRegistry);\n\nexport type LineHighlightType = \"addition\" | \"removal\" | \"highlight\";\n\ntype CodeProps = {\n language: string;\n snippet: string;\n textSize?: string;\n padding?: string;\n additionalCSS?: string;\n showLines?: boolean;\n lineCSS?: string;\n wrap?: boolean;\n lineHighlights?: Record<number, LineHighlightType>;\n};\n\nconst LINE_HIGHLIGHT_CLASSES: Record<LineHighlightType, string> = {\n addition: \"code-line-addition\",\n removal: \"code-line-removal\",\n highlight: \"code-line-highlight\",\n};\n\nconst Code = ({\n language,\n snippet,\n textSize = \"ui-text-code\",\n padding = \"p-8\",\n additionalCSS = \"\",\n showLines,\n lineCSS,\n wrap = false,\n lineHighlights,\n}: CodeProps) => {\n // Trim the snippet and remove trailing empty lines\n const trimmedSnippet = snippet.trimEnd();\n const HTMLraw = highlightSnippet(language, trimmedSnippet) ?? \"\";\n const className = `language-${language} ${textSize}`;\n\n // Calculate line count after removing trailing empty lines\n const lines = trimmedSnippet.split(/\\r\\n|\\r|\\n/);\n const lineCount = lines.length;\n\n const hasHighlights =\n lineHighlights && Object.keys(lineHighlights).length > 0;\n\n // Per-line rendering when highlights are present\n if (hasHighlights) {\n const htmlLines = splitHtmlLines(HTMLraw);\n\n return (\n <div\n className={cn(\"hljs overflow-y-auto\", padding, additionalCSS)}\n data-id=\"code\"\n >\n <pre\n lang={language}\n className={cn(\n \"h-full flex-1 text-p4 leading-normal\",\n wrap ? \"whitespace-pre-wrap break-words\" : \"overflow-x-auto\",\n )}\n >\n {htmlLines.map((lineHtml, i) => {\n const lineNum = i + 1;\n const highlightType = lineHighlights[lineNum];\n const highlightClass = highlightType\n ? LINE_HIGHLIGHT_CLASSES[highlightType]\n : undefined;\n\n return (\n <div\n key={i}\n className={cn(\"flex min-w-full\", highlightClass)}\n >\n {showLines && (\n <span\n className={cn(\n \"mr-4 font-mono text-right text-neutral-800 select-none shrink-0 inline-block\",\n lineCSS,\n )}\n style={{ minWidth: `${String(lineCount).length}ch` }}\n >\n {lineNum}\n </span>\n )}\n <code\n className={cn(className, \"flex-1 !leading-normal\")}\n dangerouslySetInnerHTML={{\n __html: lineHtml || \" \",\n }}\n />\n </div>\n );\n })}\n </pre>\n </div>\n );\n }\n\n // Default: single-block rendering (no highlights)\n return (\n <div\n className={cn(\"hljs overflow-y-auto flex\", padding, additionalCSS)}\n data-id=\"code\"\n >\n {showLines ? (\n <div className=\"text-p4 leading-normal pt-px\">\n {[...Array(lineCount)].map((_, i) => (\n <p\n className={cn(\n \"mr-4 font-mono text-right text-neutral-800\",\n lineCSS,\n )}\n key={i}\n >\n {i + 1}\n </p>\n ))}\n </div>\n ) : null}\n <pre\n lang={language}\n className={cn(\n \"h-full flex-1 text-p4 leading-normal\",\n wrap ? \"whitespace-pre-wrap break-words\" : \"overflow-x-auto\",\n )}\n >\n <code\n className={className}\n dangerouslySetInnerHTML={{ __html: HTMLraw }}\n />\n </pre>\n </div>\n );\n};\n\nexport default Code;\n"],"names":["React","highlightSnippet","registerDefaultLanguages","splitHtmlLines","languagesRegistry","cn","LINE_HIGHLIGHT_CLASSES","addition","removal","highlight","Code","language","snippet","textSize","padding","additionalCSS","showLines","lineCSS","wrap","lineHighlights","trimmedSnippet","trimEnd","HTMLraw","className","lines","split","lineCount","length","hasHighlights","Object","keys","htmlLines","div","data-id","pre","lang","map","lineHtml","i","lineNum","highlightType","highlightClass","undefined","key","span","style","minWidth","String","code","dangerouslySetInnerHTML","__html","Array","_","p"],"mappings":"AAAA,OAAOA,UAAW,OAAQ,AAC1B,QACEC,gBAAgB,CAChBC,wBAAwB,CACxBC,cAAc,KACT,4BAA6B,AACpC,QAAOC,sBAAuB,qCAAsC,AACpE,QAAOC,OAAQ,YAAa,CAE5BH,yBAAyBE,mBAgBzB,MAAME,uBAA4D,CAChEC,SAAU,qBACVC,QAAS,oBACTC,UAAW,qBACb,EAEA,MAAMC,KAAO,CAAC,CACZC,QAAQ,CACRC,OAAO,CACPC,SAAW,cAAc,CACzBC,QAAU,KAAK,CACfC,cAAgB,EAAE,CAClBC,SAAS,CACTC,OAAO,CACPC,KAAO,KAAK,CACZC,cAAc,CACJ,IAEV,MAAMC,eAAiBR,QAAQS,OAAO,GACtC,MAAMC,QAAUrB,iBAAiBU,SAAUS,iBAAmB,GAC9D,MAAMG,UAAY,CAAC,SAAS,EAAEZ,SAAS,CAAC,EAAEE,SAAS,CAAC,CAGpD,MAAMW,MAAQJ,eAAeK,KAAK,CAAC,cACnC,MAAMC,UAAYF,MAAMG,MAAM,CAE9B,MAAMC,cACJT,gBAAkBU,OAAOC,IAAI,CAACX,gBAAgBQ,MAAM,CAAG,EAGzD,GAAIC,cAAe,CACjB,MAAMG,UAAY5B,eAAemB,SAEjC,OACE,oBAACU,OACCT,UAAWlB,GAAG,uBAAwBS,QAASC,eAC/CkB,UAAQ,QAER,oBAACC,OACCC,KAAMxB,SACNY,UAAWlB,GACT,uCACAa,KAAO,kCAAoC,oBAG5Ca,UAAUK,GAAG,CAAC,CAACC,SAAUC,KACxB,MAAMC,QAAUD,EAAI,EACpB,MAAME,cAAgBrB,cAAc,CAACoB,QAAQ,CAC7C,MAAME,eAAiBD,cACnBlC,sBAAsB,CAACkC,cAAc,CACrCE,UAEJ,OACE,oBAACV,OACCW,IAAKL,EACLf,UAAWlB,GAAG,kBAAmBoC,iBAEhCzB,WACC,oBAAC4B,QACCrB,UAAWlB,GACT,+EACAY,SAEF4B,MAAO,CAAEC,SAAU,CAAC,EAAEC,OAAOrB,WAAWC,MAAM,CAAC,EAAE,CAAC,AAAC,GAElDY,SAGL,oBAACS,QACCzB,UAAWlB,GAAGkB,UAAW,0BACzB0B,wBAAyB,CACvBC,OAAQb,UAAY,QACtB,IAIR,IAIR,CAGA,OACE,oBAACL,OACCT,UAAWlB,GAAG,4BAA6BS,QAASC,eACpDkB,UAAQ,QAEPjB,UACC,oBAACgB,OAAIT,UAAU,gCACZ,IAAI4B,MAAMzB,WAAW,CAACU,GAAG,CAAC,CAACgB,EAAGd,IAC7B,oBAACe,KACC9B,UAAWlB,GACT,6CACAY,SAEF0B,IAAKL,GAEJA,EAAI,KAIT,KACJ,oBAACJ,OACCC,KAAMxB,SACNY,UAAWlB,GACT,uCACAa,KAAO,kCAAoC,oBAG7C,oBAAC8B,QACCzB,UAAWA,UACX0B,wBAAyB,CAAEC,OAAQ5B,OAAQ,KAKrD,CAEA,gBAAeZ,IAAK"}
|
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 PlainCodeView from"./CodeSnippet/PlainCodeView";import CopyButton from"./CodeSnippet/CopyButton";import SegmentedControl from"./SegmentedControl";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,wrapCode=false})=>{const codeRef=useRef(null);const[selectedApiKey,setSelectedApiKey]=useState(()=>apiKeys?.[0]?.keys?.[0]?.key??"");useEffect(()=>{if(!selectedApiKey&&apiKeys&&apiKeys.length>0){setSelectedApiKey(apiKeys[0].keys?.[0]?.key)}},[apiKeys]);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)}},[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 resolvedSdk=useMemo(()=>{if(sdkTypes.size===1&&sdk&&!sdkTypes.has(sdk)){return Array.from(sdkTypes)[0]}return sdk??null},[sdk,sdkTypes]);const showSDKSelector=sdkTypes.size>0;const filteredLanguages=useMemo(()=>{const filtered=!resolvedSdk||!showSDKSelector?[...languages]:languages.filter(lang=>lang.startsWith(`${resolvedSdk}_`));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},[resolvedSdk,showSDKSelector,languages,languageOrdering]);const activeLanguage=useMemo(()=>{if(resolvedSdk&&sdkTypes.has(resolvedSdk)){return`${resolvedSdk}_${lang}`}if(lang)return lang;if(filteredLanguages.length>0)return filteredLanguages[0];return languages[0]},[resolvedSdk,sdkTypes,lang,filteredLanguages,languages]);const requiresApiKeySubstitution=useMemo(()=>{const containsPlaceholder=codeData.some(code=>code?.content.includes("{{API_KEY}}"));return containsPlaceholder&&!!apiKeys&&apiKeys.length>0&&!!selectedApiKey},[codeData,apiKeys,selectedApiKey]);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-000 text-neutral-1300 dark:!bg-neutral-1300 dark:text-neutral-200 px-6 py-4",showLines:showCodeLines,wrap:wrapCode})}return null})},[activeLanguage,hasOnlyJsonSnippet,codeData,requiresApiKeySubstitution,showCodeLines,wrapCode,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)}},[activeLanguage,languages,onChange]);const handleLanguageChange=useCallback(language=>{if(onChange){onChange(stripSdkType(language),resolvedSdk)}},[onChange,resolvedSdk]);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 noSnippetMessage},[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-300 dark:border-neutral-1000",sdkTypes.size===1&&"p-1",headerRow?"":"rounded-t-lg")},React.createElement("div",{className:"flex gap-1 justify-start"},["realtime","rest"].map(type=>sdkTypes.has(type)&&React.createElement(SegmentedControl,{key:type,onClick:()=>handleSDKTypeChange(type),size:"xs",active:resolvedSdk===type,className:cn("text-[11px] font-semibold px-2 py-1 h-auto",sdkTypes.size===1&&"pointer-events-none bg-neutral-100 dark:bg-neutral-1200 !text-neutral-800 !dark:text-neutral-500",sdkTypes.size>1&&resolvedSdk!==type&&"bg-neutral-100 dark:bg-neutral-1200 hover:bg-neutral-200 dark:hover:bg-neutral-1100 active:bg-neutral-400 dark:active:bg-neutral-900",sdkTypes.size>1&&resolvedSdk===type&&"bg-neutral-000 dark:bg-neutral-1100")},type==="realtime"?"Realtime":"REST")))),showLanguageSelector&&(showFullSelector?React.createElement(LanguageSelector,{languages:filteredLanguages,activeLanguage:activeLanguage,onLanguageChange:handleLanguageChange}):React.createElement("div",{className:cn("border-b border-neutral-300 dark:border-neutral-1000 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)},renderContent,isHovering&&activeLanguage&&hasSnippetForActiveLanguage&&React.createElement(CopyButton,{onCopy:()=>{const text=codeData.find(code=>code.language===activeLanguage)?.content;if(text)navigator.clipboard.writeText(substituteApiKey(text,selectedApiKey,false))}})),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{parseLineHighlights}from"./utils/syntax-highlighter";import Icon from"./Icon";import{getLanguageInfo,stripSdkType}from"./CodeSnippet/languages";import LanguageSelector from"./CodeSnippet/LanguageSelector";import ApiKeySelector from"./CodeSnippet/ApiKeySelector";import PlainCodeView from"./CodeSnippet/PlainCodeView";import CopyButton from"./CodeSnippet/CopyButton";import SegmentedControl from"./SegmentedControl";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,wrapCode=false})=>{const codeRef=useRef(null);const[selectedApiKey,setSelectedApiKey]=useState(()=>apiKeys?.[0]?.keys?.[0]?.key??"");useEffect(()=>{if(!selectedApiKey&&apiKeys&&apiKeys.length>0){setSelectedApiKey(apiKeys[0].keys?.[0]?.key)}},[apiKeys]);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)}},[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 rawLanguage=extractLanguageFromCode(codeElement);if(!rawLanguage)return;const meta=codeElement.props?.["data-meta"];const{lang:codeLanguage,highlights:lineHighlights}=parseLineHighlights(rawLanguage,meta);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,lineHighlights})});return{codeData,languages,sdkTypes,isSinglePlainCommand}},[children,extractLanguageFromCode]);const resolvedSdk=useMemo(()=>{if(sdkTypes.size===1&&sdk&&!sdkTypes.has(sdk)){return Array.from(sdkTypes)[0]}return sdk??null},[sdk,sdkTypes]);const showSDKSelector=sdkTypes.size>0;const filteredLanguages=useMemo(()=>{const filtered=!resolvedSdk||!showSDKSelector?[...languages]:languages.filter(lang=>lang.startsWith(`${resolvedSdk}_`));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},[resolvedSdk,showSDKSelector,languages,languageOrdering]);const activeLanguage=useMemo(()=>{if(resolvedSdk&&sdkTypes.has(resolvedSdk)){return`${resolvedSdk}_${lang}`}if(lang)return lang;if(filteredLanguages.length>0)return filteredLanguages[0];return languages[0]},[resolvedSdk,sdkTypes,lang,filteredLanguages,languages]);const requiresApiKeySubstitution=useMemo(()=>{const containsPlaceholder=codeData.some(code=>code?.content.includes("{{API_KEY}}"));return containsPlaceholder&&!!apiKeys&&apiKeys.length>0&&!!selectedApiKey},[codeData,apiKeys,selectedApiKey]);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-000 text-neutral-1300 dark:!bg-neutral-1300 dark:text-neutral-200 px-6 py-4",showLines:showCodeLines,wrap:wrapCode,lineHighlights:Object.keys(code.lineHighlights).length>0?code.lineHighlights:undefined})}return null})},[activeLanguage,hasOnlyJsonSnippet,codeData,requiresApiKeySubstitution,showCodeLines,wrapCode,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)}},[activeLanguage,languages,onChange]);const handleLanguageChange=useCallback(language=>{if(onChange){onChange(stripSdkType(language),resolvedSdk)}},[onChange,resolvedSdk]);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 noSnippetMessage},[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-300 dark:border-neutral-1000",sdkTypes.size===1&&"p-1",headerRow?"":"rounded-t-lg")},React.createElement("div",{className:"flex gap-1 justify-start"},["realtime","rest"].map(type=>sdkTypes.has(type)&&React.createElement(SegmentedControl,{key:type,onClick:()=>handleSDKTypeChange(type),size:"xs",active:resolvedSdk===type,className:cn("text-[11px] font-semibold px-2 py-1 h-auto",sdkTypes.size===1&&"pointer-events-none bg-neutral-100 dark:bg-neutral-1200 !text-neutral-800 !dark:text-neutral-500",sdkTypes.size>1&&resolvedSdk!==type&&"bg-neutral-100 dark:bg-neutral-1200 hover:bg-neutral-200 dark:hover:bg-neutral-1100 active:bg-neutral-400 dark:active:bg-neutral-900",sdkTypes.size>1&&resolvedSdk===type&&"bg-neutral-000 dark:bg-neutral-1100")},type==="realtime"?"Realtime":"REST")))),showLanguageSelector&&(showFullSelector?React.createElement(LanguageSelector,{languages:filteredLanguages,activeLanguage:activeLanguage,onLanguageChange:handleLanguageChange}):React.createElement("div",{className:cn("border-b border-neutral-300 dark:border-neutral-1000 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)},renderContent,isHovering&&activeLanguage&&hasSnippetForActiveLanguage&&React.createElement(CopyButton,{onCopy:()=>{const text=codeData.find(code=>code.language===activeLanguage)?.content;if(text)navigator.clipboard.writeText(substituteApiKey(text,selectedApiKey,false))}})),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 PlainCodeView from \"./CodeSnippet/PlainCodeView\";\nimport CopyButton from \"./CodeSnippet/CopyButton\";\nimport SegmentedControl from \"./SegmentedControl\";\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 * Whether to wrap code content instead of scrolling\n */\n wrapCode?: boolean;\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 wrapCode = false,\n}) => {\n const codeRef = useRef<HTMLDivElement>(null);\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 // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [apiKeys]);\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 }, [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 resolvedSdk: SDKType = useMemo(() => {\n if (sdkTypes.size === 1 && sdk && !sdkTypes.has(sdk)) {\n return Array.from(sdkTypes)[0];\n }\n return sdk ?? null;\n }, [sdk, sdkTypes]);\n\n const showSDKSelector = sdkTypes.size > 0;\n\n const filteredLanguages = useMemo(() => {\n const filtered =\n !resolvedSdk || !showSDKSelector\n ? [...languages]\n : languages.filter((lang) => lang.startsWith(`${resolvedSdk}_`));\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 }, [resolvedSdk, showSDKSelector, languages, languageOrdering]);\n\n const activeLanguage = useMemo(() => {\n if (resolvedSdk && sdkTypes.has(resolvedSdk)) {\n return `${resolvedSdk}_${lang}`;\n }\n\n if (lang) return lang;\n\n if (filteredLanguages.length > 0) return filteredLanguages[0];\n\n return languages[0];\n }, [resolvedSdk, sdkTypes, lang, filteredLanguages, languages]);\n\n const requiresApiKeySubstitution = useMemo(() => {\n const containsPlaceholder = codeData.some((code) =>\n code?.content.includes(\"{{API_KEY}}\"),\n );\n\n return (\n containsPlaceholder && !!apiKeys && apiKeys.length > 0 && !!selectedApiKey\n );\n }, [codeData, apiKeys, selectedApiKey]);\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-000 text-neutral-1300 dark:!bg-neutral-1300 dark:text-neutral-200 px-6 py-4\"\n showLines={showCodeLines}\n wrap={wrapCode}\n />\n );\n }\n\n return null;\n });\n }, [\n activeLanguage,\n hasOnlyJsonSnippet,\n codeData,\n requiresApiKeySubstitution,\n showCodeLines,\n wrapCode,\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 [activeLanguage, languages, onChange],\n );\n\n const handleLanguageChange = useCallback(\n (language: string) => {\n if (onChange) {\n onChange(stripSdkType(language), resolvedSdk);\n }\n },\n [onChange, resolvedSdk],\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 <div className=\"w-12\"></div>\n </div>\n )}\n\n {showSDKSelector && (\n <div\n className={cn(\n \"p-2 border-b border-neutral-300 dark:border-neutral-1000\",\n sdkTypes.size === 1 && \"p-1\",\n headerRow ? \"\" : \"rounded-t-lg\",\n )}\n >\n <div className=\"flex gap-1 justify-start\">\n {[\"realtime\", \"rest\"].map(\n (type) =>\n sdkTypes.has(type as SDKType) && (\n <SegmentedControl\n key={type}\n onClick={() => handleSDKTypeChange(type as SDKType)}\n size=\"xs\"\n active={resolvedSdk === type}\n className={cn(\n \"text-[11px] font-semibold px-2 py-1 h-auto\",\n sdkTypes.size === 1 &&\n \"pointer-events-none bg-neutral-100 dark:bg-neutral-1200 !text-neutral-800 !dark:text-neutral-500\",\n sdkTypes.size > 1 &&\n resolvedSdk !== type &&\n \"bg-neutral-100 dark:bg-neutral-1200 hover:bg-neutral-200 dark:hover:bg-neutral-1100 active:bg-neutral-400 dark:active:bg-neutral-900\",\n sdkTypes.size > 1 &&\n resolvedSdk === type &&\n \"bg-neutral-000 dark:bg-neutral-1100\",\n )}\n >\n {type === \"realtime\" ? \"Realtime\" : \"REST\"}\n </SegmentedControl>\n ),\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-300 dark:border-neutral-1000 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 >\n {renderContent}\n {isHovering && activeLanguage && hasSnippetForActiveLanguage && (\n <CopyButton\n onCopy={() => {\n const text = codeData.find(\n (code) => code.language === activeLanguage,\n )?.content;\n if (text)\n navigator.clipboard.writeText(\n substituteApiKey(text, selectedApiKey, false),\n );\n }}\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","PlainCodeView","CopyButton","SegmentedControl","substituteApiKey","content","apiKey","mask","replace","split","CodeSnippet","fixed","headerRow","title","children","className","lang","onChange","apiKeys","sdk","showCodeLines","languageOrdering","wrapCode","codeRef","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","resolvedSdk","size","has","Array","from","showSDKSelector","filteredLanguages","filtered","filter","sort","a","b","aBase","bBase","aIndex","indexOf","bIndex","activeLanguage","requiresApiKeySubstitution","containsPlaceholder","code","isHovering","setIsHovering","hasOnlyJsonSnippet","processedChildren","targetLanguage","map","cleanLang","langInfo","processedContent","String","syntaxHighlighterKey","snippet","additionalCSS","showLines","wrap","hasSnippetForActiveLanguage","handleSDKTypeChange","type","nextLang","l","handleLanguageChange","noSnippetMessage","activeLanguageInfo","div","name","color","p","label","showLanguageSelector","showFullSelector","renderContent","plainChild","icon","onClick","active","onLanguageChange","span","ref","onMouseEnter","onMouseLeave","onFocus","onBlur","onCopy","text","navigator","clipboard","writeText","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 type { LineHighlightType } from \"./Code\";\nimport cn from \"./utils/cn\";\nimport { parseLineHighlights } from \"./utils/syntax-highlighter\";\nimport Icon from \"./Icon\";\nimport { getLanguageInfo, stripSdkType } from \"./CodeSnippet/languages\";\nimport LanguageSelector from \"./CodeSnippet/LanguageSelector\";\nimport ApiKeySelector from \"./CodeSnippet/ApiKeySelector\";\nimport PlainCodeView from \"./CodeSnippet/PlainCodeView\";\nimport CopyButton from \"./CodeSnippet/CopyButton\";\nimport SegmentedControl from \"./SegmentedControl\";\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 * Whether to wrap code content instead of scrolling\n */\n wrapCode?: boolean;\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 wrapCode = false,\n}) => {\n const codeRef = useRef<HTMLDivElement>(null);\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 // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [apiKeys]);\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 }, [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: {\n language: string;\n content: string;\n lineHighlights: Record<number, LineHighlightType>;\n }[] = [];\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 rawLanguage = extractLanguageFromCode(codeElement);\n\n if (!rawLanguage) return;\n\n const meta: string | undefined = codeElement.props?.[\"data-meta\"];\n const { lang: codeLanguage, highlights: lineHighlights } =\n parseLineHighlights(rawLanguage, meta);\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({\n language: codeLanguage,\n content: codeContent,\n lineHighlights,\n });\n });\n\n return {\n codeData,\n languages,\n sdkTypes,\n isSinglePlainCommand,\n };\n }, [children, extractLanguageFromCode]);\n\n const resolvedSdk: SDKType = useMemo(() => {\n if (sdkTypes.size === 1 && sdk && !sdkTypes.has(sdk)) {\n return Array.from(sdkTypes)[0];\n }\n return sdk ?? null;\n }, [sdk, sdkTypes]);\n\n const showSDKSelector = sdkTypes.size > 0;\n\n const filteredLanguages = useMemo(() => {\n const filtered =\n !resolvedSdk || !showSDKSelector\n ? [...languages]\n : languages.filter((lang) => lang.startsWith(`${resolvedSdk}_`));\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 }, [resolvedSdk, showSDKSelector, languages, languageOrdering]);\n\n const activeLanguage = useMemo(() => {\n if (resolvedSdk && sdkTypes.has(resolvedSdk)) {\n return `${resolvedSdk}_${lang}`;\n }\n\n if (lang) return lang;\n\n if (filteredLanguages.length > 0) return filteredLanguages[0];\n\n return languages[0];\n }, [resolvedSdk, sdkTypes, lang, filteredLanguages, languages]);\n\n const requiresApiKeySubstitution = useMemo(() => {\n const containsPlaceholder = codeData.some((code) =>\n code?.content.includes(\"{{API_KEY}}\"),\n );\n\n return (\n containsPlaceholder && !!apiKeys && apiKeys.length > 0 && !!selectedApiKey\n );\n }, [codeData, apiKeys, selectedApiKey]);\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-000 text-neutral-1300 dark:!bg-neutral-1300 dark:text-neutral-200 px-6 py-4\"\n showLines={showCodeLines}\n wrap={wrapCode}\n lineHighlights={\n Object.keys(code.lineHighlights).length > 0\n ? code.lineHighlights\n : undefined\n }\n />\n );\n }\n\n return null;\n });\n }, [\n activeLanguage,\n hasOnlyJsonSnippet,\n codeData,\n requiresApiKeySubstitution,\n showCodeLines,\n wrapCode,\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 [activeLanguage, languages, onChange],\n );\n\n const handleLanguageChange = useCallback(\n (language: string) => {\n if (onChange) {\n onChange(stripSdkType(language), resolvedSdk);\n }\n },\n [onChange, resolvedSdk],\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 <div className=\"w-12\"></div>\n </div>\n )}\n\n {showSDKSelector && (\n <div\n className={cn(\n \"p-2 border-b border-neutral-300 dark:border-neutral-1000\",\n sdkTypes.size === 1 && \"p-1\",\n headerRow ? \"\" : \"rounded-t-lg\",\n )}\n >\n <div className=\"flex gap-1 justify-start\">\n {[\"realtime\", \"rest\"].map(\n (type) =>\n sdkTypes.has(type as SDKType) && (\n <SegmentedControl\n key={type}\n onClick={() => handleSDKTypeChange(type as SDKType)}\n size=\"xs\"\n active={resolvedSdk === type}\n className={cn(\n \"text-[11px] font-semibold px-2 py-1 h-auto\",\n sdkTypes.size === 1 &&\n \"pointer-events-none bg-neutral-100 dark:bg-neutral-1200 !text-neutral-800 !dark:text-neutral-500\",\n sdkTypes.size > 1 &&\n resolvedSdk !== type &&\n \"bg-neutral-100 dark:bg-neutral-1200 hover:bg-neutral-200 dark:hover:bg-neutral-1100 active:bg-neutral-400 dark:active:bg-neutral-900\",\n sdkTypes.size > 1 &&\n resolvedSdk === type &&\n \"bg-neutral-000 dark:bg-neutral-1100\",\n )}\n >\n {type === \"realtime\" ? \"Realtime\" : \"REST\"}\n </SegmentedControl>\n ),\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-300 dark:border-neutral-1000 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 >\n {renderContent}\n {isHovering && activeLanguage && hasSnippetForActiveLanguage && (\n <CopyButton\n onCopy={() => {\n const text = codeData.find(\n (code) => code.language === activeLanguage,\n )?.content;\n if (text)\n navigator.clipboard.writeText(\n substituteApiKey(text, selectedApiKey, false),\n );\n }}\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","parseLineHighlights","Icon","getLanguageInfo","stripSdkType","LanguageSelector","ApiKeySelector","PlainCodeView","CopyButton","SegmentedControl","substituteApiKey","content","apiKey","mask","replace","split","CodeSnippet","fixed","headerRow","title","children","className","lang","onChange","apiKeys","sdk","showCodeLines","languageOrdering","wrapCode","codeRef","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","rawLanguage","meta","codeLanguage","highlights","lineHighlights","add","push","codeContent","language","resolvedSdk","size","has","Array","from","showSDKSelector","filteredLanguages","filtered","filter","sort","a","b","aBase","bBase","aIndex","indexOf","bIndex","activeLanguage","requiresApiKeySubstitution","containsPlaceholder","code","isHovering","setIsHovering","hasOnlyJsonSnippet","processedChildren","targetLanguage","map","cleanLang","langInfo","processedContent","String","syntaxHighlighterKey","snippet","additionalCSS","showLines","wrap","Object","undefined","hasSnippetForActiveLanguage","handleSDKTypeChange","type","nextLang","l","handleLanguageChange","noSnippetMessage","activeLanguageInfo","div","name","color","p","label","showLanguageSelector","showFullSelector","renderContent","plainChild","icon","onClick","active","onLanguageChange","span","ref","onMouseEnter","onMouseLeave","onFocus","onBlur","onCopy","text","navigator","clipboard","writeText","onApiKeyChange"],"mappings":"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"}
|
package/core/Meganav/data.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React from"react";import G2BestMeetsRequirementsSpring2025 from"../images/badges/g2-best-meets-requirements-spring-2025.svg";import G2BestResultsSpring2025 from"../images/badges/g2-best-results-spring-2025.svg";import G2BestSupportSpring2025 from"../images/badges/g2-best-support-spring-2025.svg";import{products}from"../ProductTile/data";import DoxyMeLogo from"../Meganav/images/cust-logo-doxy-light.png";import DoxyMeLogoDark from"../Meganav/images/cust-logo-doxy-dark.png";export const productsMenu=[{label:"Architecture",icon:"icon-gui-squares-2-x-2-outline",link:"/platform"},{label:"Integrations",icon:"icon-gui-puzzle-piece-outline",link:"/docs/platform/integrations"},{label:"SDKs",icon:"icon-gui-cube-transparent-outline",link:"/docs/sdks"},{label:"Security & Compliance",icon:"icon-gui-shield-check-outline",link:"/security-and-compliance"}];export const compareMenu=[{label:"Ably vs Pusher",link:"/compare/ably-vs-pusher"},{label:"Ably vs PubNub",link:"/compare/ably-vs-pubnub"},{label:"Ably vs Socket.io",link:"/compare/ably-vs-socketio"}];export const solutionsMenu=[{label:"Fan Engagement",icon:"icon-gui-hand-thumb-up-outline",link:"/fan-engagement",description:"Enhance every moment with live, interactive fan experiences."},{label:"FinTech",icon:"icon-gui-currency-dollar-outline",link:"/fin-tech",description:"Speed, reliability, and confidence in every user interaction."},{label:"EdTech",icon:"icon-gui-academic-cap-outline",link:"/ed-tech",description:"Power collaborative, interactive learning environments."},{label:"CXTech",icon:"icon-gui-face-smile-outline",link:"/cx-tech",description:"Deliver fast support, strong relationships, and high retention."},{label:"HealthTech",icon:"icon-gui-heartbeat-outline",link:"/health-tech",description:"Reliable tools with full data privacy and compliance."}];export const customerStoriesHighlight={companyLogo:DoxyMeLogo,companyLogoDark:DoxyMeLogoDark,companyLink:"/case-studies/doxyme",companyName:"Doxy.me",companyDesc:"built their realtime stack in under six months, cutting costs by 65%, eliminating errors, and transforming a once-feared system into a core strength."};export const companyMenu=[{label:"Our story",icon:"icon-gui-ably-badge",link:"/
|
|
1
|
+
import React from"react";import G2BestMeetsRequirementsSpring2025 from"../images/badges/g2-best-meets-requirements-spring-2025.svg";import G2BestResultsSpring2025 from"../images/badges/g2-best-results-spring-2025.svg";import G2BestSupportSpring2025 from"../images/badges/g2-best-support-spring-2025.svg";import{products}from"../ProductTile/data";import DoxyMeLogo from"../Meganav/images/cust-logo-doxy-light.png";import DoxyMeLogoDark from"../Meganav/images/cust-logo-doxy-dark.png";export const productsMenu=[{label:"Architecture",icon:"icon-gui-squares-2-x-2-outline",link:"/platform"},{label:"Integrations",icon:"icon-gui-puzzle-piece-outline",link:"/docs/platform/integrations"},{label:"SDKs",icon:"icon-gui-cube-transparent-outline",link:"/docs/sdks"},{label:"Security & Compliance",icon:"icon-gui-shield-check-outline",link:"/security-and-compliance"}];export const compareMenu=[{label:"Ably vs Pusher",link:"/compare/ably-vs-pusher"},{label:"Ably vs PubNub",link:"/compare/ably-vs-pubnub"},{label:"Ably vs Socket.io",link:"/compare/ably-vs-socketio"}];export const solutionsMenu=[{label:"Fan Engagement",icon:"icon-gui-hand-thumb-up-outline",link:"/fan-engagement",description:"Enhance every moment with live, interactive fan experiences."},{label:"FinTech",icon:"icon-gui-currency-dollar-outline",link:"/fin-tech",description:"Speed, reliability, and confidence in every user interaction."},{label:"EdTech",icon:"icon-gui-academic-cap-outline",link:"/ed-tech",description:"Power collaborative, interactive learning environments."},{label:"CXTech",icon:"icon-gui-face-smile-outline",link:"/cx-tech",description:"Deliver fast support, strong relationships, and high retention."},{label:"HealthTech",icon:"icon-gui-heartbeat-outline",link:"/health-tech",description:"Reliable tools with full data privacy and compliance."}];export const customerStoriesHighlight={companyLogo:DoxyMeLogo,companyLogoDark:DoxyMeLogoDark,companyLink:"/case-studies/doxyme",companyName:"Doxy.me",companyDesc:"built their realtime stack in under six months, cutting costs by 65%, eliminating errors, and transforming a once-feared system into a core strength."};export const companyMenu=[{label:"Our story",icon:"icon-gui-ably-badge",link:"/about"},{label:"Careers",icon:"icon-gui-briefcase-outline",link:"/careers",badge:"WE'RE HIRING"}];export const ablyAwards=[{image:G2BestSupportSpring2025,desc:"G2 Best Support Spring 2025"},{image:G2BestMeetsRequirementsSpring2025,desc:"G2 Best Meets Requirements Spring 2025"},{image:G2BestResultsSpring2025,desc:"G2 Best Results Spring 2025"}];export const menuItemLinks=[{name:"Pricing",link:"/pricing",isHiddenMobile:true},{name:"Docs",link:"/docs",isHiddenMobile:true}];export const defaultBlogPosts=[{title:"Ably AI Transport: keep your agents connected and stateful across devices",link:"/blog/ably-ai-transport",categories:["New Release","AI Transport","New Feature","RealTime Experiences","Engineering","Ably News"],pubDate:"Dec 9, 2025"},{title:"Live chat at unlimited scale: What it takes to support stadium-sized audiences",link:"/blog/live-chat-at-unlimited-scale",categories:["Chat"],pubDate:"Nov 18, 2025"}];export const productsForNav={...products,pubsub:{...products.pubsub,link:"/pubsub"},liveSync:{...products.liveSync,link:"/livesync"},chat:{...products.chat,link:"/chat"},spaces:{...products.spaces,link:"/spaces"},aiTransport:{...products.aiTransport,link:"/ai-transport"},liveObjects:{...products.liveObjects,link:"/liveobjects"}};
|
|
2
2
|
//# sourceMappingURL=data.js.map
|
package/core/Meganav/data.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/Meganav/data.tsx"],"sourcesContent":["import React from \"react\";\nimport { IconName } from \"../Icon/types\";\nimport { CustomerStoryHighlight } from \"./MeganavCustomerStories\";\nimport { BlogPost } from \"./MeganavBlog\";\nimport G2BestMeetsRequirementsSpring2025 from \"../images/badges/g2-best-meets-requirements-spring-2025.svg\";\nimport G2BestResultsSpring2025 from \"../images/badges/g2-best-results-spring-2025.svg\";\nimport G2BestSupportSpring2025 from \"../images/badges/g2-best-support-spring-2025.svg\";\nimport { products } from \"../ProductTile/data\";\nimport DoxyMeLogo from \"../Meganav/images/cust-logo-doxy-light.png\";\nimport DoxyMeLogoDark from \"../Meganav/images/cust-logo-doxy-dark.png\";\n\nexport type FlyoutPanelList = {\n label: string;\n icon?: IconName;\n link: string;\n isMobile?: boolean;\n description?: string;\n badge?: string;\n};\n\nexport type MenuItem = {\n name: string;\n link?: string;\n isHiddenMobile?: boolean;\n content?: React.ReactNode;\n panelClassName?: string;\n};\n\nexport const productsMenu: FlyoutPanelList[] = [\n {\n label: \"Architecture\",\n icon: \"icon-gui-squares-2-x-2-outline\",\n link: \"/platform\",\n },\n {\n label: \"Integrations\",\n icon: \"icon-gui-puzzle-piece-outline\",\n link: \"/docs/platform/integrations\",\n },\n {\n label: \"SDKs\",\n icon: \"icon-gui-cube-transparent-outline\",\n link: \"/docs/sdks\",\n },\n {\n label: \"Security & Compliance\",\n icon: \"icon-gui-shield-check-outline\",\n link: \"/security-and-compliance\",\n },\n];\n\nexport const compareMenu: FlyoutPanelList[] = [\n {\n label: \"Ably vs Pusher\",\n link: \"/compare/ably-vs-pusher\",\n },\n {\n label: \"Ably vs PubNub\",\n link: \"/compare/ably-vs-pubnub\",\n },\n {\n label: \"Ably vs Socket.io\",\n link: \"/compare/ably-vs-socketio\",\n },\n];\n\nexport const solutionsMenu: FlyoutPanelList[] = [\n {\n label: \"Fan Engagement\",\n icon: \"icon-gui-hand-thumb-up-outline\",\n link: \"/fan-engagement\",\n description: \"Enhance every moment with live, interactive fan experiences.\",\n },\n {\n label: \"FinTech\",\n icon: \"icon-gui-currency-dollar-outline\",\n link: \"/fin-tech\",\n description:\n \"Speed, reliability, and confidence in every user interaction.\",\n },\n {\n label: \"EdTech\",\n icon: \"icon-gui-academic-cap-outline\",\n link: \"/ed-tech\",\n description: \"Power collaborative, interactive learning environments.\",\n },\n {\n label: \"CXTech\",\n icon: \"icon-gui-face-smile-outline\",\n link: \"/cx-tech\",\n description:\n \"Deliver fast support, strong relationships, and high retention.\",\n },\n\n {\n label: \"HealthTech\",\n icon: \"icon-gui-heartbeat-outline\",\n link: \"/health-tech\",\n description: \"Reliable tools with full data privacy and compliance.\",\n },\n];\n\nexport const customerStoriesHighlight: CustomerStoryHighlight = {\n companyLogo: DoxyMeLogo,\n companyLogoDark: DoxyMeLogoDark,\n companyLink: \"/case-studies/doxyme\",\n companyName: \"Doxy.me\",\n companyDesc:\n \"built their realtime stack in under six months, cutting costs by 65%, eliminating errors, and transforming a once-feared system into a core strength.\",\n};\n\nexport const companyMenu: FlyoutPanelList[] = [\n {\n label: \"Our story\",\n icon: \"icon-gui-ably-badge\",\n link: \"/
|
|
1
|
+
{"version":3,"sources":["../../../src/core/Meganav/data.tsx"],"sourcesContent":["import React from \"react\";\nimport { IconName } from \"../Icon/types\";\nimport { CustomerStoryHighlight } from \"./MeganavCustomerStories\";\nimport { BlogPost } from \"./MeganavBlog\";\nimport G2BestMeetsRequirementsSpring2025 from \"../images/badges/g2-best-meets-requirements-spring-2025.svg\";\nimport G2BestResultsSpring2025 from \"../images/badges/g2-best-results-spring-2025.svg\";\nimport G2BestSupportSpring2025 from \"../images/badges/g2-best-support-spring-2025.svg\";\nimport { products } from \"../ProductTile/data\";\nimport DoxyMeLogo from \"../Meganav/images/cust-logo-doxy-light.png\";\nimport DoxyMeLogoDark from \"../Meganav/images/cust-logo-doxy-dark.png\";\n\nexport type FlyoutPanelList = {\n label: string;\n icon?: IconName;\n link: string;\n isMobile?: boolean;\n description?: string;\n badge?: string;\n};\n\nexport type MenuItem = {\n name: string;\n link?: string;\n isHiddenMobile?: boolean;\n content?: React.ReactNode;\n panelClassName?: string;\n};\n\nexport const productsMenu: FlyoutPanelList[] = [\n {\n label: \"Architecture\",\n icon: \"icon-gui-squares-2-x-2-outline\",\n link: \"/platform\",\n },\n {\n label: \"Integrations\",\n icon: \"icon-gui-puzzle-piece-outline\",\n link: \"/docs/platform/integrations\",\n },\n {\n label: \"SDKs\",\n icon: \"icon-gui-cube-transparent-outline\",\n link: \"/docs/sdks\",\n },\n {\n label: \"Security & Compliance\",\n icon: \"icon-gui-shield-check-outline\",\n link: \"/security-and-compliance\",\n },\n];\n\nexport const compareMenu: FlyoutPanelList[] = [\n {\n label: \"Ably vs Pusher\",\n link: \"/compare/ably-vs-pusher\",\n },\n {\n label: \"Ably vs PubNub\",\n link: \"/compare/ably-vs-pubnub\",\n },\n {\n label: \"Ably vs Socket.io\",\n link: \"/compare/ably-vs-socketio\",\n },\n];\n\nexport const solutionsMenu: FlyoutPanelList[] = [\n {\n label: \"Fan Engagement\",\n icon: \"icon-gui-hand-thumb-up-outline\",\n link: \"/fan-engagement\",\n description: \"Enhance every moment with live, interactive fan experiences.\",\n },\n {\n label: \"FinTech\",\n icon: \"icon-gui-currency-dollar-outline\",\n link: \"/fin-tech\",\n description:\n \"Speed, reliability, and confidence in every user interaction.\",\n },\n {\n label: \"EdTech\",\n icon: \"icon-gui-academic-cap-outline\",\n link: \"/ed-tech\",\n description: \"Power collaborative, interactive learning environments.\",\n },\n {\n label: \"CXTech\",\n icon: \"icon-gui-face-smile-outline\",\n link: \"/cx-tech\",\n description:\n \"Deliver fast support, strong relationships, and high retention.\",\n },\n\n {\n label: \"HealthTech\",\n icon: \"icon-gui-heartbeat-outline\",\n link: \"/health-tech\",\n description: \"Reliable tools with full data privacy and compliance.\",\n },\n];\n\nexport const customerStoriesHighlight: CustomerStoryHighlight = {\n companyLogo: DoxyMeLogo,\n companyLogoDark: DoxyMeLogoDark,\n companyLink: \"/case-studies/doxyme\",\n companyName: \"Doxy.me\",\n companyDesc:\n \"built their realtime stack in under six months, cutting costs by 65%, eliminating errors, and transforming a once-feared system into a core strength.\",\n};\n\nexport const companyMenu: FlyoutPanelList[] = [\n {\n label: \"Our story\",\n icon: \"icon-gui-ably-badge\",\n link: \"/about\",\n },\n {\n label: \"Careers\",\n icon: \"icon-gui-briefcase-outline\",\n link: \"/careers\",\n badge: \"WE'RE HIRING\",\n },\n];\n\nexport const ablyAwards = [\n {\n image: G2BestSupportSpring2025,\n desc: \"G2 Best Support Spring 2025\",\n },\n {\n image: G2BestMeetsRequirementsSpring2025,\n desc: \"G2 Best Meets Requirements Spring 2025\",\n },\n {\n image: G2BestResultsSpring2025,\n desc: \"G2 Best Results Spring 2025\",\n },\n];\n\nexport const menuItemLinks = [\n { name: \"Pricing\", link: \"/pricing\", isHiddenMobile: true },\n { name: \"Docs\", link: \"/docs\", isHiddenMobile: true },\n];\n\nexport const defaultBlogPosts: BlogPost[] = [\n {\n title:\n \"Ably AI Transport: keep your agents connected and stateful across devices\",\n link: \"/blog/ably-ai-transport\",\n categories: [\n \"New Release\",\n \"AI Transport\",\n \"New Feature\",\n \"RealTime Experiences\",\n \"Engineering\",\n \"Ably News\",\n ],\n pubDate: \"Dec 9, 2025\",\n },\n {\n title:\n \"Live chat at unlimited scale: What it takes to support stadium-sized audiences\",\n link: \"/blog/live-chat-at-unlimited-scale\",\n categories: [\"Chat\"],\n pubDate: \"Nov 18, 2025\",\n },\n];\n\nexport const productsForNav = {\n ...products,\n pubsub: { ...products.pubsub, link: \"/pubsub\" },\n liveSync: { ...products.liveSync, link: \"/livesync\" },\n chat: { ...products.chat, link: \"/chat\" },\n spaces: { ...products.spaces, link: \"/spaces\" },\n aiTransport: {\n ...products.aiTransport,\n link: \"/ai-transport\",\n },\n liveObjects: { ...products.liveObjects, link: \"/liveobjects\" },\n};\n"],"names":["React","G2BestMeetsRequirementsSpring2025","G2BestResultsSpring2025","G2BestSupportSpring2025","products","DoxyMeLogo","DoxyMeLogoDark","productsMenu","label","icon","link","compareMenu","solutionsMenu","description","customerStoriesHighlight","companyLogo","companyLogoDark","companyLink","companyName","companyDesc","companyMenu","badge","ablyAwards","image","desc","menuItemLinks","name","isHiddenMobile","defaultBlogPosts","title","categories","pubDate","productsForNav","pubsub","liveSync","chat","spaces","aiTransport","liveObjects"],"mappings":"AAAA,OAAOA,UAAW,OAAQ,AAI1B,QAAOC,sCAAuC,6DAA8D,AAC5G,QAAOC,4BAA6B,kDAAmD,AACvF,QAAOC,4BAA6B,kDAAmD,AACvF,QAASC,QAAQ,KAAQ,qBAAsB,AAC/C,QAAOC,eAAgB,4CAA6C,AACpE,QAAOC,mBAAoB,2CAA4C,AAmBvE,QAAO,MAAMC,aAAkC,CAC7C,CACEC,MAAO,eACPC,KAAM,iCACNC,KAAM,WACR,EACA,CACEF,MAAO,eACPC,KAAM,gCACNC,KAAM,6BACR,EACA,CACEF,MAAO,OACPC,KAAM,oCACNC,KAAM,YACR,EACA,CACEF,MAAO,wBACPC,KAAM,gCACNC,KAAM,0BACR,EACD,AAAC,AAEF,QAAO,MAAMC,YAAiC,CAC5C,CACEH,MAAO,iBACPE,KAAM,yBACR,EACA,CACEF,MAAO,iBACPE,KAAM,yBACR,EACA,CACEF,MAAO,oBACPE,KAAM,2BACR,EACD,AAAC,AAEF,QAAO,MAAME,cAAmC,CAC9C,CACEJ,MAAO,iBACPC,KAAM,iCACNC,KAAM,kBACNG,YAAa,8DACf,EACA,CACEL,MAAO,UACPC,KAAM,mCACNC,KAAM,YACNG,YACE,+DACJ,EACA,CACEL,MAAO,SACPC,KAAM,gCACNC,KAAM,WACNG,YAAa,yDACf,EACA,CACEL,MAAO,SACPC,KAAM,8BACNC,KAAM,WACNG,YACE,iEACJ,EAEA,CACEL,MAAO,aACPC,KAAM,6BACNC,KAAM,eACNG,YAAa,uDACf,EACD,AAAC,AAEF,QAAO,MAAMC,yBAAmD,CAC9DC,YAAaV,WACbW,gBAAiBV,eACjBW,YAAa,uBACbC,YAAa,UACbC,YACE,uJACJ,CAAE,AAEF,QAAO,MAAMC,YAAiC,CAC5C,CACEZ,MAAO,YACPC,KAAM,sBACNC,KAAM,QACR,EACA,CACEF,MAAO,UACPC,KAAM,6BACNC,KAAM,WACNW,MAAO,cACT,EACD,AAAC,AAEF,QAAO,MAAMC,WAAa,CACxB,CACEC,MAAOpB,wBACPqB,KAAM,6BACR,EACA,CACED,MAAOtB,kCACPuB,KAAM,wCACR,EACA,CACED,MAAOrB,wBACPsB,KAAM,6BACR,EACD,AAAC,AAEF,QAAO,MAAMC,cAAgB,CAC3B,CAAEC,KAAM,UAAWhB,KAAM,WAAYiB,eAAgB,IAAK,EAC1D,CAAED,KAAM,OAAQhB,KAAM,QAASiB,eAAgB,IAAK,EACrD,AAAC,AAEF,QAAO,MAAMC,iBAA+B,CAC1C,CACEC,MACE,4EACFnB,KAAM,0BACNoB,WAAY,CACV,cACA,eACA,cACA,uBACA,cACA,YACD,CACDC,QAAS,aACX,EACA,CACEF,MACE,iFACFnB,KAAM,qCACNoB,WAAY,CAAC,OAAO,CACpBC,QAAS,cACX,EACD,AAAC,AAEF,QAAO,MAAMC,eAAiB,CAC5B,GAAG5B,QAAQ,CACX6B,OAAQ,CAAE,GAAG7B,SAAS6B,MAAM,CAAEvB,KAAM,SAAU,EAC9CwB,SAAU,CAAE,GAAG9B,SAAS8B,QAAQ,CAAExB,KAAM,WAAY,EACpDyB,KAAM,CAAE,GAAG/B,SAAS+B,IAAI,CAAEzB,KAAM,OAAQ,EACxC0B,OAAQ,CAAE,GAAGhC,SAASgC,MAAM,CAAE1B,KAAM,SAAU,EAC9C2B,YAAa,CACX,GAAGjC,SAASiC,WAAW,CACvB3B,KAAM,eACR,EACA4B,YAAa,CAAE,GAAGlC,SAASkC,WAAW,CAAE5B,KAAM,cAAe,CAC/D,CAAE"}
|
|
@@ -128,4 +128,29 @@
|
|
|
128
128
|
.ui-theme-dark .hljs-tag {
|
|
129
129
|
/* purposely ignored */
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
/* Line highlighting styles */
|
|
133
|
+
.code-line-addition {
|
|
134
|
+
background-color: var(--color-green-100);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.code-line-removal {
|
|
138
|
+
background-color: var(--color-orange-100);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.code-line-highlight {
|
|
142
|
+
background-color: var(--color-blue-100);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.ui-theme-dark .code-line-addition {
|
|
146
|
+
background-color: var(--color-green-900);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.ui-theme-dark .code-line-removal {
|
|
150
|
+
background-color: var(--color-orange-1100);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.ui-theme-dark .code-line-highlight {
|
|
154
|
+
background-color: var(--color-blue-900);
|
|
155
|
+
}
|
|
131
156
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import hljs from"highlight.js/lib/core";const languageToHighlightKey=lang=>{let id;if(!lang){lang="text"}switch(lang.toLowerCase()){case"android":id="java";break;case".net":case"net":case"dotnet":case"csharp":case"c#":id="cs";break;case"objc":case"objective c":id="objectivec";break;case"laravel":id="php";break;case"flutter":id="dart";break;case"node.js":case"js":id="javascript";break;case"ts":id="typescript";break;case"kotlin":case"kt":id="kotlin";break;case"shell":case"fh":case"sh":id="bash";break;case"https":case"http":case"txt":case"plaintext":id="text";break;case"cmd":case"bat":id="dos";break;case"yml":id="yaml";break;case"erl":id="erlang";break;case"patch":id="diff";break;case"svg":id="xml";break;default:break}return id||lang};const registerDefaultLanguages=register=>{register.forEach(({key,module})=>hljs.registerLanguage(key,module))};const highlightSnippet=(languageKeyword,snippet)=>{const language=languageToHighlightKey(languageKeyword);if(typeof snippet!=="string"||!snippet||!language)return;return hljs.highlight(snippet,{language}).value};export{highlightSnippet,languageToHighlightKey,registerDefaultLanguages};
|
|
1
|
+
import hljs from"highlight.js/lib/core";const languageToHighlightKey=lang=>{let id;if(!lang){lang="text"}switch(lang.toLowerCase()){case"android":id="java";break;case".net":case"net":case"dotnet":case"csharp":case"c#":id="cs";break;case"objc":case"objective c":id="objectivec";break;case"laravel":id="php";break;case"flutter":id="dart";break;case"node.js":case"js":id="javascript";break;case"ts":id="typescript";break;case"kotlin":case"kt":id="kotlin";break;case"shell":case"fh":case"sh":id="bash";break;case"https":case"http":case"txt":case"plaintext":id="text";break;case"cmd":case"bat":id="dos";break;case"yml":id="yaml";break;case"erl":id="erlang";break;case"patch":id="diff";break;case"svg":id="xml";break;default:break}return id||lang};const registerDefaultLanguages=register=>{register.forEach(({key,module})=>hljs.registerLanguage(key,module))};const highlightSnippet=(languageKeyword,snippet)=>{const language=languageToHighlightKey(languageKeyword);if(typeof snippet!=="string"||!snippet||!language)return;return hljs.highlight(snippet,{language}).value};const parseLineHighlights=(languageString,meta)=>{if(!meta){return{lang:languageString,highlights:{}}}const match=meta.match(/highlight=["']?([^"']+)["']?/);if(!match){return{lang:languageString,highlights:{}}}const spec=match[1];const highlights={};const tokens=spec.split(",");for(const token of tokens){const trimmed=token.trim();if(!trimmed)continue;let type="highlight";let rangePart=trimmed;if(trimmed.startsWith("+")){type="addition";rangePart=trimmed.slice(1)}else if(trimmed.startsWith("-")){type="removal";rangePart=trimmed.slice(1)}const rangeMatch=rangePart.match(/^(\d+)(?:-(\d+))?$/);if(!rangeMatch)continue;const start=parseInt(rangeMatch[1],10);const end=rangeMatch[2]?parseInt(rangeMatch[2],10):start;for(let i=start;i<=end;i++){highlights[i]=type}}return{lang:languageString,highlights}};const splitHtmlLines=html=>{const rawLines=html.split("\n");const result=[];let openTags=[];for(const rawLine of rawLines){let line=openTags.join("")+rawLine;const openMatches=rawLine.match(/<span[^>]*>/g)||[];const closeMatches=rawLine.match(/<\/span>/g)||[];for(const tag of openMatches){openTags.push(tag)}for(let i=0;i<closeMatches.length;i++){openTags.pop()}for(let i=0;i<openTags.length;i++){line+="</span>"}result.push(line)}return result};export{highlightSnippet,languageToHighlightKey,parseLineHighlights,registerDefaultLanguages,splitHtmlLines};
|
|
2
2
|
//# sourceMappingURL=syntax-highlighter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/utils/syntax-highlighter.js"],"sourcesContent":["import hljs from \"highlight.js/lib/core\";\n\n// Map certain frameworks, protocols etc to available langauage packs\nconst languageToHighlightKey = (lang) => {\n let id;\n\n if (!lang) {\n lang = \"text\";\n }\n\n switch (lang.toLowerCase()) {\n case \"android\":\n id = \"java\";\n break;\n\n case \".net\":\n case \"net\":\n case \"dotnet\":\n case \"csharp\":\n case \"c#\":\n id = \"cs\";\n break;\n\n case \"objc\":\n case \"objective c\":\n id = \"objectivec\";\n break;\n\n case \"laravel\":\n id = \"php\";\n break;\n\n case \"flutter\":\n id = \"dart\";\n break;\n\n case \"node.js\":\n case \"js\":\n id = \"javascript\";\n break;\n\n case \"ts\":\n id = \"typescript\";\n break;\n\n case \"kotlin\":\n case \"kt\":\n id = \"kotlin\";\n break;\n\n case \"shell\":\n case \"fh\":\n case \"sh\":\n id = \"bash\";\n break;\n\n case \"https\":\n case \"http\":\n case \"txt\":\n case \"plaintext\":\n id = \"text\";\n break;\n\n case \"cmd\":\n case \"bat\":\n id = \"dos\";\n break;\n\n case \"yml\":\n id = \"yaml\";\n break;\n\n case \"erl\":\n id = \"erlang\";\n break;\n\n case \"patch\":\n id = \"diff\";\n break;\n\n case \"svg\":\n id = \"xml\";\n break;\n\n default:\n break;\n }\n\n return id || lang;\n};\n\nconst registerDefaultLanguages = (register) => {\n register.forEach(({ key, module }) => hljs.registerLanguage(key, module));\n};\n\nconst highlightSnippet = (languageKeyword, snippet) => {\n const language = languageToHighlightKey(languageKeyword);\n if (typeof snippet !== \"string\" || !snippet || !language) return;\n\n return hljs.highlight(snippet, { language }).value;\n};\n\
|
|
1
|
+
{"version":3,"sources":["../../../src/core/utils/syntax-highlighter.js"],"sourcesContent":["import hljs from \"highlight.js/lib/core\";\n\n// Map certain frameworks, protocols etc to available langauage packs\nconst languageToHighlightKey = (lang) => {\n let id;\n\n if (!lang) {\n lang = \"text\";\n }\n\n switch (lang.toLowerCase()) {\n case \"android\":\n id = \"java\";\n break;\n\n case \".net\":\n case \"net\":\n case \"dotnet\":\n case \"csharp\":\n case \"c#\":\n id = \"cs\";\n break;\n\n case \"objc\":\n case \"objective c\":\n id = \"objectivec\";\n break;\n\n case \"laravel\":\n id = \"php\";\n break;\n\n case \"flutter\":\n id = \"dart\";\n break;\n\n case \"node.js\":\n case \"js\":\n id = \"javascript\";\n break;\n\n case \"ts\":\n id = \"typescript\";\n break;\n\n case \"kotlin\":\n case \"kt\":\n id = \"kotlin\";\n break;\n\n case \"shell\":\n case \"fh\":\n case \"sh\":\n id = \"bash\";\n break;\n\n case \"https\":\n case \"http\":\n case \"txt\":\n case \"plaintext\":\n id = \"text\";\n break;\n\n case \"cmd\":\n case \"bat\":\n id = \"dos\";\n break;\n\n case \"yml\":\n id = \"yaml\";\n break;\n\n case \"erl\":\n id = \"erlang\";\n break;\n\n case \"patch\":\n id = \"diff\";\n break;\n\n case \"svg\":\n id = \"xml\";\n break;\n\n default:\n break;\n }\n\n return id || lang;\n};\n\nconst registerDefaultLanguages = (register) => {\n register.forEach(({ key, module }) => hljs.registerLanguage(key, module));\n};\n\nconst highlightSnippet = (languageKeyword, snippet) => {\n const language = languageToHighlightKey(languageKeyword);\n if (typeof snippet !== \"string\" || !snippet || !language) return;\n\n return hljs.highlight(snippet, { language }).value;\n};\n\n/**\n * Parse line highlight specifications from the code fence meta string.\n *\n * A remark plugin preserves the meta as a `data-meta` attribute on the <code>\n * element. Components read it and pass it here as the `meta` parameter.\n *\n * Syntax (in meta string): `highlight=\"+1-3,-5,7\"`\n * - `+` prefix: addition (green)\n * - `-` prefix: removal (red)\n * - no prefix: neutral highlight (blue)\n * - `N-M`: inclusive line range\n * - comma-separated for multiple specs\n *\n * @param {string} languageString - the language, e.g. \"javascript\"\n * @param {string} [meta] - the code fence meta string, e.g. 'highlight=\"+1-3,-5,7\"'\n * @returns {{ lang: string, highlights: Record<number, 'addition' | 'removal' | 'highlight'> }}\n */\nconst parseLineHighlights = (languageString, meta) => {\n if (!meta) {\n return { lang: languageString, highlights: {} };\n }\n\n const match = meta.match(/highlight=[\"']?([^\"']+)[\"']?/);\n if (!match) {\n return { lang: languageString, highlights: {} };\n }\n\n const spec = match[1];\n const highlights = {};\n\n const tokens = spec.split(\",\");\n for (const token of tokens) {\n const trimmed = token.trim();\n if (!trimmed) continue;\n\n let type = \"highlight\";\n let rangePart = trimmed;\n\n if (trimmed.startsWith(\"+\")) {\n type = \"addition\";\n rangePart = trimmed.slice(1);\n } else if (trimmed.startsWith(\"-\")) {\n type = \"removal\";\n rangePart = trimmed.slice(1);\n }\n\n const rangeMatch = rangePart.match(/^(\\d+)(?:-(\\d+))?$/);\n if (!rangeMatch) continue;\n\n const start = parseInt(rangeMatch[1], 10);\n const end = rangeMatch[2] ? parseInt(rangeMatch[2], 10) : start;\n\n for (let i = start; i <= end; i++) {\n highlights[i] = type;\n }\n }\n\n return { lang: languageString, highlights };\n};\n\n/**\n * Split highlighted HTML by newlines, repairing any spans that cross\n * line boundaries so each line fragment is valid HTML.\n *\n * @param {string} html - HTML string produced by highlight.js\n * @returns {string[]} one HTML fragment per source line\n */\nconst splitHtmlLines = (html) => {\n const rawLines = html.split(\"\\n\");\n const result = [];\n let openTags = [];\n\n for (const rawLine of rawLines) {\n let line = openTags.join(\"\") + rawLine;\n\n const openMatches = rawLine.match(/<span[^>]*>/g) || [];\n const closeMatches = rawLine.match(/<\\/span>/g) || [];\n\n for (const tag of openMatches) {\n openTags.push(tag);\n }\n for (let i = 0; i < closeMatches.length; i++) {\n openTags.pop();\n }\n\n for (let i = 0; i < openTags.length; i++) {\n line += \"</span>\";\n }\n\n result.push(line);\n }\n\n return result;\n};\n\nexport {\n highlightSnippet,\n languageToHighlightKey,\n parseLineHighlights,\n registerDefaultLanguages,\n splitHtmlLines,\n};\n"],"names":["hljs","languageToHighlightKey","lang","id","toLowerCase","registerDefaultLanguages","register","forEach","key","module","registerLanguage","highlightSnippet","languageKeyword","snippet","language","highlight","value","parseLineHighlights","languageString","meta","highlights","match","spec","tokens","split","token","trimmed","trim","type","rangePart","startsWith","slice","rangeMatch","start","parseInt","end","i","splitHtmlLines","html","rawLines","result","openTags","rawLine","line","join","openMatches","closeMatches","tag","push","length","pop"],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -311,6 +311,7 @@ function highlightEl(el: any): void;
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
declare module '@ably/ui/core/Code' {
|
|
314
|
+
export type LineHighlightType = "addition" | "removal" | "highlight";
|
|
314
315
|
type CodeProps = {
|
|
315
316
|
language: string;
|
|
316
317
|
snippet: string;
|
|
@@ -320,8 +321,9 @@ type CodeProps = {
|
|
|
320
321
|
showLines?: boolean;
|
|
321
322
|
lineCSS?: string;
|
|
322
323
|
wrap?: boolean;
|
|
324
|
+
lineHighlights?: Record<number, LineHighlightType>;
|
|
323
325
|
};
|
|
324
|
-
const Code: ({ language, snippet, textSize, padding, additionalCSS, showLines, lineCSS, wrap, }: CodeProps) => import("react/jsx-runtime").JSX.Element;
|
|
326
|
+
const Code: ({ language, snippet, textSize, padding, additionalCSS, showLines, lineCSS, wrap, lineHighlights, }: CodeProps) => import("react/jsx-runtime").JSX.Element;
|
|
325
327
|
export default Code;
|
|
326
328
|
//# sourceMappingURL=Code.d.ts.map
|
|
327
329
|
}
|
|
@@ -6593,7 +6595,36 @@ const registry: {
|
|
|
6593
6595
|
declare module '@ably/ui/core/utils/syntax-highlighter' {
|
|
6594
6596
|
export function highlightSnippet(languageKeyword: any, snippet: any): string | undefined;
|
|
6595
6597
|
export function languageToHighlightKey(lang: any): any;
|
|
6598
|
+
/**
|
|
6599
|
+
* Parse line highlight specifications from the code fence meta string.
|
|
6600
|
+
*
|
|
6601
|
+
* A remark plugin preserves the meta as a `data-meta` attribute on the <code>
|
|
6602
|
+
* element. Components read it and pass it here as the `meta` parameter.
|
|
6603
|
+
*
|
|
6604
|
+
* Syntax (in meta string): `highlight="+1-3,-5,7"`
|
|
6605
|
+
* - `+` prefix: addition (green)
|
|
6606
|
+
* - `-` prefix: removal (red)
|
|
6607
|
+
* - no prefix: neutral highlight (blue)
|
|
6608
|
+
* - `N-M`: inclusive line range
|
|
6609
|
+
* - comma-separated for multiple specs
|
|
6610
|
+
*
|
|
6611
|
+
* @param {string} languageString - the language, e.g. "javascript"
|
|
6612
|
+
* @param {string} [meta] - the code fence meta string, e.g. 'highlight="+1-3,-5,7"'
|
|
6613
|
+
* @returns {{ lang: string, highlights: Record<number, 'addition' | 'removal' | 'highlight'> }}
|
|
6614
|
+
*/
|
|
6615
|
+
export function parseLineHighlights(languageString: string, meta?: string): {
|
|
6616
|
+
lang: string;
|
|
6617
|
+
highlights: Record<number, "addition" | "removal" | "highlight">;
|
|
6618
|
+
};
|
|
6596
6619
|
export function registerDefaultLanguages(register: any): void;
|
|
6620
|
+
/**
|
|
6621
|
+
* Split highlighted HTML by newlines, repairing any spans that cross
|
|
6622
|
+
* line boundaries so each line fragment is valid HTML.
|
|
6623
|
+
*
|
|
6624
|
+
* @param {string} html - HTML string produced by highlight.js
|
|
6625
|
+
* @returns {string[]} one HTML fragment per source line
|
|
6626
|
+
*/
|
|
6627
|
+
export function splitHtmlLines(html: string): string[];
|
|
6597
6628
|
//# sourceMappingURL=syntax-highlighter.d.ts.map
|
|
6598
6629
|
}
|
|
6599
6630
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ably/ui",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.14.0-dev.1101c91c8f",
|
|
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",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"@types/react": "^18.3.1",
|
|
38
38
|
"@types/react-dom": "^18.3.0",
|
|
39
39
|
"@types/svg-sprite": "^0.0.39",
|
|
40
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
41
|
-
"@typescript-eslint/parser": "^8.
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
41
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
42
42
|
"@vitejs/plugin-react-swc": "^4.0.1",
|
|
43
43
|
"@vitest/browser": "3.2.4",
|
|
44
44
|
"@vitest/coverage-v8": "3.2.4",
|
|
@@ -53,11 +53,11 @@
|
|
|
53
53
|
"heroicons": "^2.2.0",
|
|
54
54
|
"http-server": "14.1.1",
|
|
55
55
|
"jsdom": "^27.4.0",
|
|
56
|
-
"mixpanel-browser": "^2.
|
|
56
|
+
"mixpanel-browser": "^2.74.0",
|
|
57
57
|
"msw": "2.12.0",
|
|
58
58
|
"msw-storybook-addon": "^2.0.5",
|
|
59
|
-
"playwright": "^1.
|
|
60
|
-
"posthog-js": "^1.
|
|
59
|
+
"playwright": "^1.58.0",
|
|
60
|
+
"posthog-js": "^1.336.1",
|
|
61
61
|
"prettier": "^3.8.0",
|
|
62
62
|
"storybook": "^10.2.0",
|
|
63
63
|
"svg-sprite": "^2.0.4",
|