@ably/ui 17.14.0-dev.2fa7246503 → 17.14.0-dev.65b2d6dd35

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/README.md CHANGED
@@ -269,22 +269,25 @@ After the above, you should have:
269
269
  To deploy a review app with your in-progress code, you can use the `pre-release` script:
270
270
 
271
271
  ```bash
272
- # in root
273
- scripts/pre-release.sh
272
+ # in packages/ui directory
273
+ ./scripts/pre-release.sh
274
274
  ```
275
275
 
276
- This script is a combination of two scripts:
276
+ This script automates the following steps:
277
277
 
278
278
  1. Pre-Release:
279
279
 
280
- - update your local dependencies for ably-ui and run a production build
281
- - release an NPM package with the version built from your current SemVer but adding a pre-release tag based on a short SHA of your HEAD commit
280
+ - Updates local dependencies for ably-ui and runs a production build
281
+ - Releases an NPM package with the version built from your current SemVer but adding a pre-release tag based on a short SHA of your HEAD commit
282
+ - Waits for the package to be available on the NPM registry (handles propagation delay)
283
+ - Automatically updates both `apps/website` and `apps/voltaire` with the new dev version
282
284
 
283
285
  2. Update Pre-Release Version:
284
286
 
285
- - commit all the above and push to origin
287
+ - Commits all changes (UI package.json, app package.json files, and lockfiles) in a single atomic commit
288
+ - Pushes the commit and tag to origin
286
289
 
287
- This will trigger a build of the review app.
290
+ This will trigger a build of the review app with the pre-release version installed in both consuming apps.
288
291
 
289
292
  ### Components
290
293
 
@@ -339,13 +342,13 @@ We use [Semantic Versioning 2.0.0](https://semver.org/) to version different lib
339
342
 
340
343
  Packages are published to the [GitHub private registry](https://github.com/features/packages).
341
344
 
342
- Publishing is done by tagging a release in GitHub. This triggers a GitHub action that pushes to the private NPM registry as well as publishing new artefacts in the CDN, with the version taken from the tag of the GitHub release.
345
+ Publishing is done by tagging a release in GitHub. This triggers a GitHub action that pushes to the NPM registry as well as deploying Storybook to the [ably/ably-ui](https://github.com/ably/ably-ui) repository, with the version taken from the tag of the GitHub release.
343
346
 
344
- This will trigger GitHub actions in supported apps (currently [Voltaire](http://github.com/ably/voltaire) & [Website](http://github.com/ably/website)) to create a PR with an ably-ui version update.
347
+ After publishing, you can manually trigger the `update-ably-ui` workflow to create a single draft PR that updates both [Voltaire](http://github.com/ably/voltaire) and [Website](http://github.com/ably/website) with the new ably-ui version.
345
348
 
346
349
  **To trigger a release:**
347
350
 
348
- - Make sure you have run pre-release script `./pre-release.sh` (This updates the npm package version for ably-ui in `package.json`).
351
+ - Make sure you have run the pre-release script `./scripts/pre-release.sh` (This updates the npm package version for ably-ui in `package.json` and updates both consuming apps).
349
352
  - Merge your PR into `main` after it has been approved.
350
353
  - On the Github [Ably-UI](http://github.com/ably/ably-ui) repo, [create a new release](https://github.com/ably/ably-ui/releases/new) tag.
351
354
  - Create a new tag with the new version number for the release.
@@ -354,9 +357,10 @@ This will trigger GitHub actions in supported apps (currently [Voltaire](http://
354
357
  - Click on the Autogenerate release notes button.
355
358
  - Publish Release.
356
359
  - Check the Github `Actions` tab in the repo to make sure the release is green.
357
- - Upon successful release, a compiled version of the Storybook site will be deployed to Github Pages.
360
+ - Upon successful release, a compiled version of the Storybook site will be deployed to the [ably/ably-ui](https://github.com/ably/ably-ui) repository's gh-pages branch.
361
+ - Manually trigger the `update-ably-ui` workflow from the Actions tab to create a draft PR updating both apps.
358
362
 
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/).
363
+ This will publish the package to NPM and deploy a new Storybook site to [https://ably.github.io/ably-ui/](https://ably.github.io/ably-ui/). To update the consuming apps, manually trigger the workflow, which will create a single draft PR for both Voltaire and Website that requires review before merging.
360
364
 
361
365
  ### Tagging Convention (Monorepo)
362
366
 
@@ -0,0 +1,2 @@
1
+ import React from"react";import{describe,expect,it}from"vitest";import{render}from"@testing-library/react";import Code from"../Code";describe("Code",()=>{it("renders a single <code> element when no highlights are present",()=>{const{container}=render(React.createElement(Code,{language:"javascript",snippet:'var x = "hello";'}));const codeElements=container.querySelectorAll("pre > code");expect(codeElements.length).toBe(1)});it("wraps highlighted lines in a single <code> element",()=>{const{container}=render(React.createElement(Code,{language:"javascript",snippet:'var x = "hello";\nvar y = "world";',lineHighlights:{1:"addition"}}));const pre=container.querySelector("pre");const codeElements=pre?.querySelectorAll("code");expect(codeElements?.length).toBe(1);const lineSpans=codeElements?.[0].querySelectorAll(":scope > span");expect(lineSpans?.length).toBe(2)});it("applies highlight classes to the correct lines",()=>{const{container}=render(React.createElement(Code,{language:"javascript",snippet:"line1\nline2\nline3",lineHighlights:{1:"addition",3:"removal"}}));const lineWrappers=container.querySelectorAll("pre > code > span");expect(lineWrappers.length).toBe(3);expect(lineWrappers[0].classList.contains("code-line-addition")).toBe(true);expect(lineWrappers[1].classList.contains("code-line-addition")).toBe(false);expect(lineWrappers[2].classList.contains("code-line-removal")).toBe(true)})});
2
+ //# sourceMappingURL=Code.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/Code/Code.test.tsx"],"sourcesContent":["/**\n * @vitest-environment jsdom\n */\n\nimport React from \"react\";\nimport { describe, expect, it } from \"vitest\";\nimport { render } from \"@testing-library/react\";\n\nimport Code from \"../Code\";\n\ndescribe(\"Code\", () => {\n it(\"renders a single <code> element when no highlights are present\", () => {\n const { container } = render(\n <Code language=\"javascript\" snippet={'var x = \"hello\";'} />,\n );\n const codeElements = container.querySelectorAll(\"pre > code\");\n expect(codeElements.length).toBe(1);\n });\n\n it(\"wraps highlighted lines in a single <code> element\", () => {\n const { container } = render(\n <Code\n language=\"javascript\"\n snippet={'var x = \"hello\";\\nvar y = \"world\";'}\n lineHighlights={{ 1: \"addition\" }}\n />,\n );\n\n const pre = container.querySelector(\"pre\");\n const codeElements = pre?.querySelectorAll(\"code\");\n expect(codeElements?.length).toBe(1);\n\n // Line content spans should be inside the <code>\n const lineSpans = codeElements?.[0].querySelectorAll(\":scope > span\");\n expect(lineSpans?.length).toBe(2);\n });\n\n it(\"applies highlight classes to the correct lines\", () => {\n const { container } = render(\n <Code\n language=\"javascript\"\n snippet={\"line1\\nline2\\nline3\"}\n lineHighlights={{ 1: \"addition\", 3: \"removal\" }}\n />,\n );\n\n const lineWrappers = container.querySelectorAll(\"pre > code > span\");\n expect(lineWrappers.length).toBe(3);\n expect(lineWrappers[0].classList.contains(\"code-line-addition\")).toBe(true);\n expect(lineWrappers[1].classList.contains(\"code-line-addition\")).toBe(\n false,\n );\n expect(lineWrappers[2].classList.contains(\"code-line-removal\")).toBe(true);\n });\n});\n"],"names":["React","describe","expect","it","render","Code","container","language","snippet","codeElements","querySelectorAll","length","toBe","lineHighlights","pre","querySelector","lineSpans","lineWrappers","classList","contains"],"mappings":"AAIA,OAAOA,UAAW,OAAQ,AAC1B,QAASC,QAAQ,CAAEC,MAAM,CAAEC,EAAE,KAAQ,QAAS,AAC9C,QAASC,MAAM,KAAQ,wBAAyB,AAEhD,QAAOC,SAAU,SAAU,CAE3BJ,SAAS,OAAQ,KACfE,GAAG,iEAAkE,KACnE,KAAM,CAAEG,SAAS,CAAE,CAAGF,OACpB,oBAACC,MAAKE,SAAS,aAAaC,QAAS,sBAEvC,MAAMC,aAAeH,UAAUI,gBAAgB,CAAC,cAChDR,OAAOO,aAAaE,MAAM,EAAEC,IAAI,CAAC,EACnC,GAEAT,GAAG,qDAAsD,KACvD,KAAM,CAAEG,SAAS,CAAE,CAAGF,OACpB,oBAACC,MACCE,SAAS,aACTC,QAAS,qCACTK,eAAgB,CAAE,EAAG,UAAW,KAIpC,MAAMC,IAAMR,UAAUS,aAAa,CAAC,OACpC,MAAMN,aAAeK,KAAKJ,iBAAiB,QAC3CR,OAAOO,cAAcE,QAAQC,IAAI,CAAC,GAGlC,MAAMI,UAAYP,cAAc,CAAC,EAAE,CAACC,iBAAiB,iBACrDR,OAAOc,WAAWL,QAAQC,IAAI,CAAC,EACjC,GAEAT,GAAG,iDAAkD,KACnD,KAAM,CAAEG,SAAS,CAAE,CAAGF,OACpB,oBAACC,MACCE,SAAS,aACTC,QAAS,sBACTK,eAAgB,CAAE,EAAG,WAAY,EAAG,SAAU,KAIlD,MAAMI,aAAeX,UAAUI,gBAAgB,CAAC,qBAChDR,OAAOe,aAAaN,MAAM,EAAEC,IAAI,CAAC,GACjCV,OAAOe,YAAY,CAAC,EAAE,CAACC,SAAS,CAACC,QAAQ,CAAC,uBAAuBP,IAAI,CAAC,MACtEV,OAAOe,YAAY,CAAC,EAAE,CAACC,SAAS,CAACC,QAAQ,CAAC,uBAAuBP,IAAI,CACnE,OAEFV,OAAOe,YAAY,CAAC,EAAE,CAACC,SAAS,CAACC,QAAQ,CAAC,sBAAsBP,IAAI,CAAC,KACvE,EACF"}
package/core/Code.js CHANGED
@@ -1,2 +1,2 @@
1
- import React from"react";import{highlightSnippet,LINE_HIGHLIGHT_CLASSES,registerDefaultLanguages,splitHtmlLines}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,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||"&nbsp;"}}))})))}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,LINE_HIGHLIGHT_CLASSES,registerDefaultLanguages,splitHtmlLines}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,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")},React.createElement("code",{className:className},htmlLines.map((lineHtml,i)=>{const lineNum=i+1;const highlightType=lineHighlights[lineNum];const highlightClass=highlightType?LINE_HIGHLIGHT_CLASSES[highlightType]:undefined;return React.createElement("span",{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("span",{className:"flex-1 !leading-normal",dangerouslySetInnerHTML:{__html:lineHtml||"&nbsp;"}}))}))))}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 LINE_HIGHLIGHT_CLASSES,\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 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 || \"&nbsp;\",\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","LINE_HIGHLIGHT_CLASSES","registerDefaultLanguages","splitHtmlLines","languagesRegistry","cn","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,sBAAsB,CACtBC,wBAAwB,CACxBC,cAAc,KACT,4BAA6B,AACpC,QAAOC,sBAAuB,qCAAsC,AACpE,QAAOC,OAAQ,YAAa,CAE5BH,yBAAyBE,mBAgBzB,MAAME,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,QAAUlB,iBAAiBO,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,UAAYxB,eAAee,SAEjC,OACE,oBAACU,OACCT,UAAWd,GAAG,uBAAwBK,QAASC,eAC/CkB,UAAQ,QAER,oBAACC,OACCC,KAAMxB,SACNY,UAAWd,GACT,uCACAS,KAAO,kCAAoC,oBAG5Ca,UAAUK,GAAG,CAAC,CAACC,SAAUC,KACxB,MAAMC,QAAUD,EAAI,EACpB,MAAME,cAAgBrB,cAAc,CAACoB,QAAQ,CAC7C,MAAME,eAAiBD,cACnBnC,sBAAsB,CAACmC,cAAc,CACrCE,UAEJ,OACE,oBAACV,OACCW,IAAKL,EACLf,UAAWd,GAAG,kBAAmBgC,iBAEhCzB,WACC,oBAAC4B,QACCrB,UAAWd,GACT,+EACAQ,SAEF4B,MAAO,CAAEC,SAAU,CAAC,EAAEC,OAAOrB,WAAWC,MAAM,CAAC,EAAE,CAAC,AAAC,GAElDY,SAGL,oBAACS,QACCzB,UAAWd,GAAGc,UAAW,0BACzB0B,wBAAyB,CACvBC,OAAQb,UAAY,QACtB,IAIR,IAIR,CAGA,OACE,oBAACL,OACCT,UAAWd,GAAG,4BAA6BK,QAASC,eACpDkB,UAAQ,QAEPjB,UACC,oBAACgB,OAAIT,UAAU,gCACZ,IAAI4B,MAAMzB,WAAW,CAACU,GAAG,CAAC,CAACgB,EAAGd,IAC7B,oBAACe,KACC9B,UAAWd,GACT,6CACAQ,SAEF0B,IAAKL,GAEJA,EAAI,KAIT,KACJ,oBAACJ,OACCC,KAAMxB,SACNY,UAAWd,GACT,uCACAS,KAAO,kCAAoC,oBAG7C,oBAAC8B,QACCzB,UAAWA,UACX0B,wBAAyB,CAAEC,OAAQ5B,OAAQ,KAKrD,CAEA,gBAAeZ,IAAK"}
1
+ {"version":3,"sources":["../../src/core/Code.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n highlightSnippet,\n LINE_HIGHLIGHT_CLASSES,\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 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 <code className={className}>\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 <span key={i} className={cn(\"flex min-w-full\", highlightClass)}>\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 <span\n className=\"flex-1 !leading-normal\"\n dangerouslySetInnerHTML={{\n __html: lineHtml || \"&nbsp;\",\n }}\n />\n </span>\n );\n })}\n </code>\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","LINE_HIGHLIGHT_CLASSES","registerDefaultLanguages","splitHtmlLines","languagesRegistry","cn","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","code","map","lineHtml","i","lineNum","highlightType","highlightClass","undefined","span","key","style","minWidth","String","dangerouslySetInnerHTML","__html","Array","_","p"],"mappings":"AAAA,OAAOA,UAAW,OAAQ,AAC1B,QACEC,gBAAgB,CAChBC,sBAAsB,CACtBC,wBAAwB,CACxBC,cAAc,KACT,4BAA6B,AACpC,QAAOC,sBAAuB,qCAAsC,AACpE,QAAOC,OAAQ,YAAa,CAE5BH,yBAAyBE,mBAgBzB,MAAME,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,QAAUlB,iBAAiBO,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,UAAYxB,eAAee,SAEjC,OACE,oBAACU,OACCT,UAAWd,GAAG,uBAAwBK,QAASC,eAC/CkB,UAAQ,QAER,oBAACC,OACCC,KAAMxB,SACNY,UAAWd,GACT,uCACAS,KAAO,kCAAoC,oBAG7C,oBAACkB,QAAKb,UAAWA,WACdQ,UAAUM,GAAG,CAAC,CAACC,SAAUC,KACxB,MAAMC,QAAUD,EAAI,EACpB,MAAME,cAAgBtB,cAAc,CAACqB,QAAQ,CAC7C,MAAME,eAAiBD,cACnBpC,sBAAsB,CAACoC,cAAc,CACrCE,UAEJ,OACE,oBAACC,QAAKC,IAAKN,EAAGhB,UAAWd,GAAG,kBAAmBiC,iBAC5C1B,WACC,oBAAC4B,QACCrB,UAAWd,GACT,+EACAQ,SAEF6B,MAAO,CAAEC,SAAU,CAAC,EAAEC,OAAOtB,WAAWC,MAAM,CAAC,EAAE,CAAC,AAAC,GAElDa,SAGL,oBAACI,QACCrB,UAAU,yBACV0B,wBAAyB,CACvBC,OAAQZ,UAAY,QACtB,IAIR,KAKV,CAGA,OACE,oBAACN,OACCT,UAAWd,GAAG,4BAA6BK,QAASC,eACpDkB,UAAQ,QAEPjB,UACC,oBAACgB,OAAIT,UAAU,gCACZ,IAAI4B,MAAMzB,WAAW,CAACW,GAAG,CAAC,CAACe,EAAGb,IAC7B,oBAACc,KACC9B,UAAWd,GACT,6CACAQ,SAEF4B,IAAKN,GAEJA,EAAI,KAIT,KACJ,oBAACL,OACCC,KAAMxB,SACNY,UAAWd,GACT,uCACAS,KAAO,kCAAoC,oBAG7C,oBAACkB,QACCb,UAAWA,UACX0B,wBAAyB,CAAEC,OAAQ5B,OAAQ,KAKrD,CAEA,gBAAeZ,IAAK"}
@@ -1,2 +1,2 @@
1
- const languages={javascript:{label:"JavaScript",icon:"icon-tech-javascript",syntaxHighlighterKey:"javascript"},typescript:{label:"TypeScript",icon:"icon-tech-typescript",syntaxHighlighterKey:"typescript"},java:{label:"Java",icon:"icon-tech-java",syntaxHighlighterKey:"java"},kotlin:{label:"Kotlin",icon:"icon-tech-kotlin",syntaxHighlighterKey:"kotlin"},python:{label:"Python",icon:"icon-tech-python",syntaxHighlighterKey:"python"},csharp:{label:"C#",icon:"icon-tech-csharp",syntaxHighlighterKey:"csharp"},go:{label:"Go",icon:"icon-tech-go",syntaxHighlighterKey:"go"},ruby:{label:"Ruby",icon:"icon-tech-ruby",syntaxHighlighterKey:"ruby"},php:{label:"PHP",icon:"icon-tech-php",syntaxHighlighterKey:"php"},nodejs:{label:"Node.js",icon:"icon-tech-nodejs",syntaxHighlighterKey:"javascript"},react:{label:"React",icon:"icon-tech-react",syntaxHighlighterKey:"javascript"},html:{label:"HTML",icon:"icon-tech-web",syntaxHighlighterKey:"xml"},shell:{label:"Shell",icon:"icon-tech-web",syntaxHighlighterKey:"bash"},json:{label:"JSON",icon:"icon-tech-json",syntaxHighlighterKey:"json"},laravel:{label:"Laravel",icon:"icon-tech-laravel-broadcast",syntaxHighlighterKey:"php"},xml:{label:"XML",icon:"icon-tech-web",syntaxHighlighterKey:"xml"},sql:{label:"SQL",icon:"icon-tech-postgres",syntaxHighlighterKey:"sql"},swift:{label:"Swift",icon:"icon-tech-swift",syntaxHighlighterKey:"swift"},cpp:{label:"C++",icon:"icon-tech-web",syntaxHighlighterKey:"cpp"},dart:{label:"Dart",icon:"icon-tech-web",syntaxHighlighterKey:"dart"},objc:{label:"Objective-C",icon:"icon-tech-objectivec",syntaxHighlighterKey:"objc"},android:{label:"Android",icon:"icon-tech-android-head",syntaxHighlighterKey:"java"},flutter:{label:"Flutter",icon:"icon-tech-flutter",syntaxHighlighterKey:"dart"},jetpack:{label:"Jetpack Compose",icon:"icon-tech-jetpack",syntaxHighlighterKey:"kotlin"}};export const stripSdkType=lang=>{if(lang.startsWith("realtime_")||lang.startsWith("rest_")){return lang.split("_").slice(1).join("_")}return lang};export const getLanguageInfo=langKey=>{const key=stripSdkType(langKey).toLowerCase();if(languages[key]){return languages[key]}return{label:langKey,icon:"icon-tech-web",syntaxHighlighterKey:langKey}};export default languages;
1
+ const languages={javascript:{label:"JavaScript",icon:"icon-tech-javascript",syntaxHighlighterKey:"javascript"},typescript:{label:"TypeScript",icon:"icon-tech-typescript",syntaxHighlighterKey:"typescript"},java:{label:"Java",icon:"icon-tech-java",syntaxHighlighterKey:"java"},kotlin:{label:"Kotlin",icon:"icon-tech-kotlin",syntaxHighlighterKey:"kotlin"},python:{label:"Python",icon:"icon-tech-python",syntaxHighlighterKey:"python"},csharp:{label:"C#",icon:"icon-tech-csharp",syntaxHighlighterKey:"csharp"},go:{label:"Go",icon:"icon-tech-go",syntaxHighlighterKey:"go"},ruby:{label:"Ruby",icon:"icon-tech-ruby",syntaxHighlighterKey:"ruby"},php:{label:"PHP",icon:"icon-tech-php",syntaxHighlighterKey:"php"},nodejs:{label:"Node.js",icon:"icon-tech-nodejs",syntaxHighlighterKey:"javascript"},react:{label:"React",icon:"icon-tech-react",syntaxHighlighterKey:"javascript"},html:{label:"HTML",icon:"icon-tech-web",syntaxHighlighterKey:"xml"},shell:{label:"Shell",icon:"icon-tech-web",syntaxHighlighterKey:"bash"},json:{label:"JSON",icon:"icon-tech-json",syntaxHighlighterKey:"json"},laravel:{label:"Laravel",icon:"icon-tech-laravel-broadcast",syntaxHighlighterKey:"php"},xml:{label:"XML",icon:"icon-tech-web",syntaxHighlighterKey:"xml"},sql:{label:"SQL",icon:"icon-tech-postgres",syntaxHighlighterKey:"sql"},swift:{label:"Swift",icon:"icon-tech-swift",syntaxHighlighterKey:"swift"},cpp:{label:"C++",icon:"icon-tech-web",syntaxHighlighterKey:"cpp"},dart:{label:"Dart",icon:"icon-tech-web",syntaxHighlighterKey:"dart"},objc:{label:"Objective-C",icon:"icon-tech-objectivec",syntaxHighlighterKey:"objc"},android:{label:"Android",icon:"icon-tech-android-full",syntaxHighlighterKey:"kotlin"},flutter:{label:"Flutter",icon:"icon-tech-flutter",syntaxHighlighterKey:"dart"}};export const stripSdkType=lang=>{if(lang.startsWith("realtime_")||lang.startsWith("rest_")){return lang.split("_").slice(1).join("_")}return lang};export const getLanguageInfo=langKey=>{const key=stripSdkType(langKey).toLowerCase();if(languages[key]){return languages[key]}return{label:langKey,icon:"icon-tech-web",syntaxHighlighterKey:langKey}};export default languages;
2
2
  //# sourceMappingURL=languages.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/CodeSnippet/languages.ts"],"sourcesContent":["import { IconName } from \"../Icon/types\";\n\nexport interface LanguageInfo {\n label: string;\n icon: IconName;\n syntaxHighlighterKey?: string;\n}\n\nexport type LanguageMap = Record<string, LanguageInfo>;\n\nconst languages: LanguageMap = {\n javascript: {\n label: \"JavaScript\",\n icon: \"icon-tech-javascript\",\n syntaxHighlighterKey: \"javascript\",\n },\n typescript: {\n label: \"TypeScript\",\n icon: \"icon-tech-typescript\",\n syntaxHighlighterKey: \"typescript\",\n },\n java: {\n label: \"Java\",\n icon: \"icon-tech-java\",\n syntaxHighlighterKey: \"java\",\n },\n kotlin: {\n label: \"Kotlin\",\n icon: \"icon-tech-kotlin\",\n syntaxHighlighterKey: \"kotlin\",\n },\n python: {\n label: \"Python\",\n icon: \"icon-tech-python\",\n syntaxHighlighterKey: \"python\",\n },\n csharp: {\n label: \"C#\",\n icon: \"icon-tech-csharp\",\n syntaxHighlighterKey: \"csharp\",\n },\n go: {\n label: \"Go\",\n icon: \"icon-tech-go\",\n syntaxHighlighterKey: \"go\",\n },\n ruby: {\n label: \"Ruby\",\n icon: \"icon-tech-ruby\",\n syntaxHighlighterKey: \"ruby\",\n },\n php: {\n label: \"PHP\",\n icon: \"icon-tech-php\",\n syntaxHighlighterKey: \"php\",\n },\n nodejs: {\n label: \"Node.js\",\n icon: \"icon-tech-nodejs\",\n syntaxHighlighterKey: \"javascript\",\n },\n react: {\n label: \"React\",\n icon: \"icon-tech-react\",\n syntaxHighlighterKey: \"javascript\",\n },\n html: {\n label: \"HTML\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"xml\",\n },\n shell: {\n label: \"Shell\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"bash\",\n },\n json: {\n label: \"JSON\",\n icon: \"icon-tech-json\",\n syntaxHighlighterKey: \"json\",\n },\n laravel: {\n label: \"Laravel\",\n icon: \"icon-tech-laravel-broadcast\",\n syntaxHighlighterKey: \"php\",\n },\n xml: {\n label: \"XML\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"xml\",\n },\n sql: {\n label: \"SQL\",\n icon: \"icon-tech-postgres\",\n syntaxHighlighterKey: \"sql\",\n },\n swift: {\n label: \"Swift\",\n icon: \"icon-tech-swift\",\n syntaxHighlighterKey: \"swift\",\n },\n // New entries from languageInfo.ts\n cpp: {\n label: \"C++\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"cpp\",\n },\n dart: {\n label: \"Dart\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"dart\",\n },\n objc: {\n label: \"Objective-C\",\n icon: \"icon-tech-objectivec\",\n syntaxHighlighterKey: \"objc\",\n },\n android: {\n label: \"Android\",\n icon: \"icon-tech-android-head\",\n syntaxHighlighterKey: \"java\",\n },\n flutter: {\n label: \"Flutter\",\n icon: \"icon-tech-flutter\",\n syntaxHighlighterKey: \"dart\",\n },\n jetpack: {\n label: \"Jetpack Compose\",\n icon: \"icon-tech-jetpack\",\n syntaxHighlighterKey: \"kotlin\",\n },\n};\n\nexport const stripSdkType = (lang: string) => {\n if (lang.startsWith(\"realtime_\") || lang.startsWith(\"rest_\")) {\n return lang.split(\"_\").slice(1).join(\"_\");\n }\n return lang;\n};\n\n// Fallback function to handle languages not in the map\nexport const getLanguageInfo = (langKey: string): LanguageInfo => {\n const key = stripSdkType(langKey).toLowerCase();\n\n if (languages[key]) {\n return languages[key];\n }\n\n // Fallback for unknown languages\n return {\n label: langKey,\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: langKey,\n };\n};\n\nexport default languages;\n"],"names":["languages","javascript","label","icon","syntaxHighlighterKey","typescript","java","kotlin","python","csharp","go","ruby","php","nodejs","react","html","shell","json","laravel","xml","sql","swift","cpp","dart","objc","android","flutter","jetpack","stripSdkType","lang","startsWith","split","slice","join","getLanguageInfo","langKey","key","toLowerCase"],"mappings":"AAUA,MAAMA,UAAyB,CAC7BC,WAAY,CACVC,MAAO,aACPC,KAAM,uBACNC,qBAAsB,YACxB,EACAC,WAAY,CACVH,MAAO,aACPC,KAAM,uBACNC,qBAAsB,YACxB,EACAE,KAAM,CACJJ,MAAO,OACPC,KAAM,iBACNC,qBAAsB,MACxB,EACAG,OAAQ,CACNL,MAAO,SACPC,KAAM,mBACNC,qBAAsB,QACxB,EACAI,OAAQ,CACNN,MAAO,SACPC,KAAM,mBACNC,qBAAsB,QACxB,EACAK,OAAQ,CACNP,MAAO,KACPC,KAAM,mBACNC,qBAAsB,QACxB,EACAM,GAAI,CACFR,MAAO,KACPC,KAAM,eACNC,qBAAsB,IACxB,EACAO,KAAM,CACJT,MAAO,OACPC,KAAM,iBACNC,qBAAsB,MACxB,EACAQ,IAAK,CACHV,MAAO,MACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAS,OAAQ,CACNX,MAAO,UACPC,KAAM,mBACNC,qBAAsB,YACxB,EACAU,MAAO,CACLZ,MAAO,QACPC,KAAM,kBACNC,qBAAsB,YACxB,EACAW,KAAM,CACJb,MAAO,OACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAY,MAAO,CACLd,MAAO,QACPC,KAAM,gBACNC,qBAAsB,MACxB,EACAa,KAAM,CACJf,MAAO,OACPC,KAAM,iBACNC,qBAAsB,MACxB,EACAc,QAAS,CACPhB,MAAO,UACPC,KAAM,8BACNC,qBAAsB,KACxB,EACAe,IAAK,CACHjB,MAAO,MACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAgB,IAAK,CACHlB,MAAO,MACPC,KAAM,qBACNC,qBAAsB,KACxB,EACAiB,MAAO,CACLnB,MAAO,QACPC,KAAM,kBACNC,qBAAsB,OACxB,EAEAkB,IAAK,CACHpB,MAAO,MACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAmB,KAAM,CACJrB,MAAO,OACPC,KAAM,gBACNC,qBAAsB,MACxB,EACAoB,KAAM,CACJtB,MAAO,cACPC,KAAM,uBACNC,qBAAsB,MACxB,EACAqB,QAAS,CACPvB,MAAO,UACPC,KAAM,yBACNC,qBAAsB,MACxB,EACAsB,QAAS,CACPxB,MAAO,UACPC,KAAM,oBACNC,qBAAsB,MACxB,EACAuB,QAAS,CACPzB,MAAO,kBACPC,KAAM,oBACNC,qBAAsB,QACxB,CACF,CAEA,QAAO,MAAMwB,aAAe,AAACC,OAC3B,GAAIA,KAAKC,UAAU,CAAC,cAAgBD,KAAKC,UAAU,CAAC,SAAU,CAC5D,OAAOD,KAAKE,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAGC,IAAI,CAAC,IACvC,CACA,OAAOJ,IACT,CAAE,AAGF,QAAO,MAAMK,gBAAkB,AAACC,UAC9B,MAAMC,IAAMR,aAAaO,SAASE,WAAW,GAE7C,GAAIrC,SAAS,CAACoC,IAAI,CAAE,CAClB,OAAOpC,SAAS,CAACoC,IAAI,AACvB,CAGA,MAAO,CACLlC,MAAOiC,QACPhC,KAAM,gBACNC,qBAAsB+B,OACxB,CACF,CAAE,AAEF,gBAAenC,SAAU"}
1
+ {"version":3,"sources":["../../../src/core/CodeSnippet/languages.ts"],"sourcesContent":["import { IconName } from \"../Icon/types\";\n\nexport interface LanguageInfo {\n label: string;\n icon: IconName;\n syntaxHighlighterKey?: string;\n}\n\nexport type LanguageMap = Record<string, LanguageInfo>;\n\nconst languages: LanguageMap = {\n javascript: {\n label: \"JavaScript\",\n icon: \"icon-tech-javascript\",\n syntaxHighlighterKey: \"javascript\",\n },\n typescript: {\n label: \"TypeScript\",\n icon: \"icon-tech-typescript\",\n syntaxHighlighterKey: \"typescript\",\n },\n java: {\n label: \"Java\",\n icon: \"icon-tech-java\",\n syntaxHighlighterKey: \"java\",\n },\n kotlin: {\n label: \"Kotlin\",\n icon: \"icon-tech-kotlin\",\n syntaxHighlighterKey: \"kotlin\",\n },\n python: {\n label: \"Python\",\n icon: \"icon-tech-python\",\n syntaxHighlighterKey: \"python\",\n },\n csharp: {\n label: \"C#\",\n icon: \"icon-tech-csharp\",\n syntaxHighlighterKey: \"csharp\",\n },\n go: {\n label: \"Go\",\n icon: \"icon-tech-go\",\n syntaxHighlighterKey: \"go\",\n },\n ruby: {\n label: \"Ruby\",\n icon: \"icon-tech-ruby\",\n syntaxHighlighterKey: \"ruby\",\n },\n php: {\n label: \"PHP\",\n icon: \"icon-tech-php\",\n syntaxHighlighterKey: \"php\",\n },\n nodejs: {\n label: \"Node.js\",\n icon: \"icon-tech-nodejs\",\n syntaxHighlighterKey: \"javascript\",\n },\n react: {\n label: \"React\",\n icon: \"icon-tech-react\",\n syntaxHighlighterKey: \"javascript\",\n },\n html: {\n label: \"HTML\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"xml\",\n },\n shell: {\n label: \"Shell\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"bash\",\n },\n json: {\n label: \"JSON\",\n icon: \"icon-tech-json\",\n syntaxHighlighterKey: \"json\",\n },\n laravel: {\n label: \"Laravel\",\n icon: \"icon-tech-laravel-broadcast\",\n syntaxHighlighterKey: \"php\",\n },\n xml: {\n label: \"XML\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"xml\",\n },\n sql: {\n label: \"SQL\",\n icon: \"icon-tech-postgres\",\n syntaxHighlighterKey: \"sql\",\n },\n swift: {\n label: \"Swift\",\n icon: \"icon-tech-swift\",\n syntaxHighlighterKey: \"swift\",\n },\n // New entries from languageInfo.ts\n cpp: {\n label: \"C++\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"cpp\",\n },\n dart: {\n label: \"Dart\",\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: \"dart\",\n },\n objc: {\n label: \"Objective-C\",\n icon: \"icon-tech-objectivec\",\n syntaxHighlighterKey: \"objc\",\n },\n android: {\n label: \"Android\",\n icon: \"icon-tech-android-full\",\n syntaxHighlighterKey: \"kotlin\",\n },\n flutter: {\n label: \"Flutter\",\n icon: \"icon-tech-flutter\",\n syntaxHighlighterKey: \"dart\",\n },\n};\n\nexport const stripSdkType = (lang: string) => {\n if (lang.startsWith(\"realtime_\") || lang.startsWith(\"rest_\")) {\n return lang.split(\"_\").slice(1).join(\"_\");\n }\n return lang;\n};\n\n// Fallback function to handle languages not in the map\nexport const getLanguageInfo = (langKey: string): LanguageInfo => {\n const key = stripSdkType(langKey).toLowerCase();\n\n if (languages[key]) {\n return languages[key];\n }\n\n // Fallback for unknown languages\n return {\n label: langKey,\n icon: \"icon-tech-web\",\n syntaxHighlighterKey: langKey,\n };\n};\n\nexport default languages;\n"],"names":["languages","javascript","label","icon","syntaxHighlighterKey","typescript","java","kotlin","python","csharp","go","ruby","php","nodejs","react","html","shell","json","laravel","xml","sql","swift","cpp","dart","objc","android","flutter","stripSdkType","lang","startsWith","split","slice","join","getLanguageInfo","langKey","key","toLowerCase"],"mappings":"AAUA,MAAMA,UAAyB,CAC7BC,WAAY,CACVC,MAAO,aACPC,KAAM,uBACNC,qBAAsB,YACxB,EACAC,WAAY,CACVH,MAAO,aACPC,KAAM,uBACNC,qBAAsB,YACxB,EACAE,KAAM,CACJJ,MAAO,OACPC,KAAM,iBACNC,qBAAsB,MACxB,EACAG,OAAQ,CACNL,MAAO,SACPC,KAAM,mBACNC,qBAAsB,QACxB,EACAI,OAAQ,CACNN,MAAO,SACPC,KAAM,mBACNC,qBAAsB,QACxB,EACAK,OAAQ,CACNP,MAAO,KACPC,KAAM,mBACNC,qBAAsB,QACxB,EACAM,GAAI,CACFR,MAAO,KACPC,KAAM,eACNC,qBAAsB,IACxB,EACAO,KAAM,CACJT,MAAO,OACPC,KAAM,iBACNC,qBAAsB,MACxB,EACAQ,IAAK,CACHV,MAAO,MACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAS,OAAQ,CACNX,MAAO,UACPC,KAAM,mBACNC,qBAAsB,YACxB,EACAU,MAAO,CACLZ,MAAO,QACPC,KAAM,kBACNC,qBAAsB,YACxB,EACAW,KAAM,CACJb,MAAO,OACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAY,MAAO,CACLd,MAAO,QACPC,KAAM,gBACNC,qBAAsB,MACxB,EACAa,KAAM,CACJf,MAAO,OACPC,KAAM,iBACNC,qBAAsB,MACxB,EACAc,QAAS,CACPhB,MAAO,UACPC,KAAM,8BACNC,qBAAsB,KACxB,EACAe,IAAK,CACHjB,MAAO,MACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAgB,IAAK,CACHlB,MAAO,MACPC,KAAM,qBACNC,qBAAsB,KACxB,EACAiB,MAAO,CACLnB,MAAO,QACPC,KAAM,kBACNC,qBAAsB,OACxB,EAEAkB,IAAK,CACHpB,MAAO,MACPC,KAAM,gBACNC,qBAAsB,KACxB,EACAmB,KAAM,CACJrB,MAAO,OACPC,KAAM,gBACNC,qBAAsB,MACxB,EACAoB,KAAM,CACJtB,MAAO,cACPC,KAAM,uBACNC,qBAAsB,MACxB,EACAqB,QAAS,CACPvB,MAAO,UACPC,KAAM,yBACNC,qBAAsB,QACxB,EACAsB,QAAS,CACPxB,MAAO,UACPC,KAAM,oBACNC,qBAAsB,MACxB,CACF,CAEA,QAAO,MAAMuB,aAAe,AAACC,OAC3B,GAAIA,KAAKC,UAAU,CAAC,cAAgBD,KAAKC,UAAU,CAAC,SAAU,CAC5D,OAAOD,KAAKE,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAGC,IAAI,CAAC,IACvC,CACA,OAAOJ,IACT,CAAE,AAGF,QAAO,MAAMK,gBAAkB,AAACC,UAC9B,MAAMC,IAAMR,aAAaO,SAASE,WAAW,GAE7C,GAAIpC,SAAS,CAACmC,IAAI,CAAE,CAClB,OAAOnC,SAAS,CAACmC,IAAI,AACvB,CAGA,MAAO,CACLjC,MAAOgC,QACP/B,KAAM,gBACNC,qBAAsB8B,OACxB,CACF,CAAE,AAEF,gBAAelC,SAAU"}
@@ -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};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};const LINE_HIGHLIGHT_CLASSES={addition:"code-line-addition",removal:"code-line-removal",highlight:"code-line-highlight"};export{highlightSnippet,languageToHighlightKey,LINE_HIGHLIGHT_CLASSES,parseLineHighlights,registerDefaultLanguages,splitHtmlLines};
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 tagPattern=/<(\/?)span([^>]*)>/g;let m;while((m=tagPattern.exec(rawLine))!==null){if(m[1]==="/"){openTags.pop()}else{openTags.push(m[0])}}for(let i=0;i<openTags.length;i++){line+="</span>"}result.push(line)}return result};const LINE_HIGHLIGHT_CLASSES={addition:"code-line-addition",removal:"code-line-removal",highlight:"code-line-highlight"};export{highlightSnippet,languageToHighlightKey,LINE_HIGHLIGHT_CLASSES,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\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\nconst LINE_HIGHLIGHT_CLASSES = {\n addition: \"code-line-addition\",\n removal: \"code-line-removal\",\n highlight: \"code-line-highlight\",\n};\n\nexport {\n highlightSnippet,\n languageToHighlightKey,\n LINE_HIGHLIGHT_CLASSES,\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","LINE_HIGHLIGHT_CLASSES","addition","removal"],"mappings":"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"}
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 a meta string.\n *\n * Syntax: `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] - string containing highlight specs, 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 // Process open/close tags in document order\n const tagPattern = /<(\\/?)span([^>]*)>/g;\n let m;\n while ((m = tagPattern.exec(rawLine)) !== null) {\n if (m[1] === \"/\") {\n openTags.pop();\n } else {\n openTags.push(m[0]);\n }\n }\n\n // Close any tags still open so this line is valid HTML\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\nconst LINE_HIGHLIGHT_CLASSES = {\n addition: \"code-line-addition\",\n removal: \"code-line-removal\",\n highlight: \"code-line-highlight\",\n};\n\nexport {\n highlightSnippet,\n languageToHighlightKey,\n LINE_HIGHLIGHT_CLASSES,\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","tagPattern","m","exec","pop","push","length","LINE_HIGHLIGHT_CLASSES","addition","removal"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{describe,expect,it}from"vitest";import{splitHtmlLines,parseLineHighlights}from"./syntax-highlighter";describe("splitHtmlLines",()=>{it("splits plain text with no spans",()=>{expect(splitHtmlLines("hello\nworld")).toEqual(["hello","world"])});it("repairs a span crossing a line boundary",()=>{const html='<span class="a">hello\nworld</span>';expect(splitHtmlLines(html)).toEqual(['<span class="a">hello</span>','<span class="a">world</span>'])});it("handles close then open on the same line",()=>{const html='<span class="a">first\n</span><span class="b">second\nthird</span>';const result=splitHtmlLines(html);expect(result[0]).toBe('<span class="a">first</span>');expect(result[1]).toBe('<span class="a"></span><span class="b">second</span>');expect(result[2]).toBe('<span class="b">third</span>')});it("re-opens nested spans crossing lines",()=>{const html='<span class="a"><span class="b">text\nmore</span></span>';const result=splitHtmlLines(html);expect(result[0]).toBe('<span class="a"><span class="b">text</span></span>');expect(result[1]).toBe('<span class="a"><span class="b">more</span></span>')});it("preserves empty lines",()=>{expect(splitHtmlLines("line1\n\nline3")).toEqual(["line1","","line3"])});it("does not carry forward complete spans on one line",()=>{const html='<span class="a">x</span><span class="b">y</span>\nnext';expect(splitHtmlLines(html)).toEqual(['<span class="a">x</span><span class="b">y</span>',"next"])});it("handles a single line with no newlines",()=>{expect(splitHtmlLines('<span class="a">hello</span>')).toEqual(['<span class="a">hello</span>'])})});describe("parseLineHighlights",()=>{it("returns empty highlights when no meta is provided",()=>{expect(parseLineHighlights("javascript")).toEqual({lang:"javascript",highlights:{}})});it("parses addition ranges",()=>{const result=parseLineHighlights("js",'highlight="+1-3"');expect(result.highlights).toEqual({1:"addition",2:"addition",3:"addition"})});it("parses removal lines",()=>{const result=parseLineHighlights("js",'highlight="-5"');expect(result.highlights).toEqual({5:"removal"})});it("parses neutral highlight lines",()=>{const result=parseLineHighlights("js",'highlight="7"');expect(result.highlights).toEqual({7:"highlight"})});it("parses mixed specs",()=>{const result=parseLineHighlights("js",'highlight="+1-3,-5,7"');expect(result.highlights).toEqual({1:"addition",2:"addition",3:"addition",5:"removal",7:"highlight"})})});
2
+ //# sourceMappingURL=syntax-highlighter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/utils/syntax-highlighter.test.js"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\n\nimport { splitHtmlLines, parseLineHighlights } from \"./syntax-highlighter\";\n\ndescribe(\"splitHtmlLines\", () => {\n it(\"splits plain text with no spans\", () => {\n expect(splitHtmlLines(\"hello\\nworld\")).toEqual([\"hello\", \"world\"]);\n });\n\n it(\"repairs a span crossing a line boundary\", () => {\n const html = '<span class=\"a\">hello\\nworld</span>';\n expect(splitHtmlLines(html)).toEqual([\n '<span class=\"a\">hello</span>',\n '<span class=\"a\">world</span>',\n ]);\n });\n\n it(\"handles close then open on the same line\", () => {\n const html =\n '<span class=\"a\">first\\n</span><span class=\"b\">second\\nthird</span>';\n const result = splitHtmlLines(html);\n\n // Line 1: carries nothing, opens \"a\" → \"first\" with closing tag\n expect(result[0]).toBe('<span class=\"a\">first</span>');\n // Line 2: carries \"a\", raw line closes \"a\" then opens \"b\" → only \"b\" open\n expect(result[1]).toBe(\n '<span class=\"a\"></span><span class=\"b\">second</span>',\n );\n // Line 3: carries only \"b\"\n expect(result[2]).toBe('<span class=\"b\">third</span>');\n });\n\n it(\"re-opens nested spans crossing lines\", () => {\n const html = '<span class=\"a\"><span class=\"b\">text\\nmore</span></span>';\n const result = splitHtmlLines(html);\n expect(result[0]).toBe(\n '<span class=\"a\"><span class=\"b\">text</span></span>',\n );\n expect(result[1]).toBe(\n '<span class=\"a\"><span class=\"b\">more</span></span>',\n );\n });\n\n it(\"preserves empty lines\", () => {\n expect(splitHtmlLines(\"line1\\n\\nline3\")).toEqual([\"line1\", \"\", \"line3\"]);\n });\n\n it(\"does not carry forward complete spans on one line\", () => {\n const html = '<span class=\"a\">x</span><span class=\"b\">y</span>\\nnext';\n expect(splitHtmlLines(html)).toEqual([\n '<span class=\"a\">x</span><span class=\"b\">y</span>',\n \"next\",\n ]);\n });\n\n it(\"handles a single line with no newlines\", () => {\n expect(splitHtmlLines('<span class=\"a\">hello</span>')).toEqual([\n '<span class=\"a\">hello</span>',\n ]);\n });\n});\n\ndescribe(\"parseLineHighlights\", () => {\n it(\"returns empty highlights when no meta is provided\", () => {\n expect(parseLineHighlights(\"javascript\")).toEqual({\n lang: \"javascript\",\n highlights: {},\n });\n });\n\n it(\"parses addition ranges\", () => {\n const result = parseLineHighlights(\"js\", 'highlight=\"+1-3\"');\n expect(result.highlights).toEqual({\n 1: \"addition\",\n 2: \"addition\",\n 3: \"addition\",\n });\n });\n\n it(\"parses removal lines\", () => {\n const result = parseLineHighlights(\"js\", 'highlight=\"-5\"');\n expect(result.highlights).toEqual({ 5: \"removal\" });\n });\n\n it(\"parses neutral highlight lines\", () => {\n const result = parseLineHighlights(\"js\", 'highlight=\"7\"');\n expect(result.highlights).toEqual({ 7: \"highlight\" });\n });\n\n it(\"parses mixed specs\", () => {\n const result = parseLineHighlights(\"js\", 'highlight=\"+1-3,-5,7\"');\n expect(result.highlights).toEqual({\n 1: \"addition\",\n 2: \"addition\",\n 3: \"addition\",\n 5: \"removal\",\n 7: \"highlight\",\n });\n });\n});\n"],"names":["describe","expect","it","splitHtmlLines","parseLineHighlights","toEqual","html","result","toBe","lang","highlights"],"mappings":"AAAA,OAASA,QAAQ,CAAEC,MAAM,CAAEC,EAAE,KAAQ,QAAS,AAE9C,QAASC,cAAc,CAAEC,mBAAmB,KAAQ,sBAAuB,CAE3EJ,SAAS,iBAAkB,KACzBE,GAAG,kCAAmC,KACpCD,OAAOE,eAAe,iBAAiBE,OAAO,CAAC,CAAC,QAAS,QAAQ,CACnE,GAEAH,GAAG,0CAA2C,KAC5C,MAAMI,KAAO,sCACbL,OAAOE,eAAeG,OAAOD,OAAO,CAAC,CACnC,+BACA,+BACD,CACH,GAEAH,GAAG,2CAA4C,KAC7C,MAAMI,KACJ,qEACF,MAAMC,OAASJ,eAAeG,MAG9BL,OAAOM,MAAM,CAAC,EAAE,EAAEC,IAAI,CAAC,gCAEvBP,OAAOM,MAAM,CAAC,EAAE,EAAEC,IAAI,CACpB,wDAGFP,OAAOM,MAAM,CAAC,EAAE,EAAEC,IAAI,CAAC,+BACzB,GAEAN,GAAG,uCAAwC,KACzC,MAAMI,KAAO,2DACb,MAAMC,OAASJ,eAAeG,MAC9BL,OAAOM,MAAM,CAAC,EAAE,EAAEC,IAAI,CACpB,sDAEFP,OAAOM,MAAM,CAAC,EAAE,EAAEC,IAAI,CACpB,qDAEJ,GAEAN,GAAG,wBAAyB,KAC1BD,OAAOE,eAAe,mBAAmBE,OAAO,CAAC,CAAC,QAAS,GAAI,QAAQ,CACzE,GAEAH,GAAG,oDAAqD,KACtD,MAAMI,KAAO,yDACbL,OAAOE,eAAeG,OAAOD,OAAO,CAAC,CACnC,mDACA,OACD,CACH,GAEAH,GAAG,yCAA0C,KAC3CD,OAAOE,eAAe,iCAAiCE,OAAO,CAAC,CAC7D,+BACD,CACH,EACF,GAEAL,SAAS,sBAAuB,KAC9BE,GAAG,oDAAqD,KACtDD,OAAOG,oBAAoB,eAAeC,OAAO,CAAC,CAChDI,KAAM,aACNC,WAAY,CAAC,CACf,EACF,GAEAR,GAAG,yBAA0B,KAC3B,MAAMK,OAASH,oBAAoB,KAAM,oBACzCH,OAAOM,OAAOG,UAAU,EAAEL,OAAO,CAAC,CAChC,EAAG,WACH,EAAG,WACH,EAAG,UACL,EACF,GAEAH,GAAG,uBAAwB,KACzB,MAAMK,OAASH,oBAAoB,KAAM,kBACzCH,OAAOM,OAAOG,UAAU,EAAEL,OAAO,CAAC,CAAE,EAAG,SAAU,EACnD,GAEAH,GAAG,iCAAkC,KACnC,MAAMK,OAASH,oBAAoB,KAAM,iBACzCH,OAAOM,OAAOG,UAAU,EAAEL,OAAO,CAAC,CAAE,EAAG,WAAY,EACrD,GAEAH,GAAG,qBAAsB,KACvB,MAAMK,OAASH,oBAAoB,KAAM,yBACzCH,OAAOM,OAAOG,UAAU,EAAEL,OAAO,CAAC,CAChC,EAAG,WACH,EAAG,WACH,EAAG,WACH,EAAG,UACH,EAAG,WACL,EACF,EACF"}
package/index.d.ts CHANGED
@@ -304,6 +304,14 @@ export default Button;
304
304
  //# sourceMappingURL=Button.d.ts.map
305
305
  }
306
306
 
307
+ declare module '@ably/ui/core/Code/Code.test' {
308
+ /**
309
+ * @vitest-environment jsdom
310
+ */
311
+ export {};
312
+ //# sourceMappingURL=Code.test.d.ts.map
313
+ }
314
+
307
315
  declare module '@ably/ui/core/Code/component' {
308
316
  export default highlightEl;
309
317
  function highlightEl(el: any): void;
@@ -6601,12 +6609,9 @@ export namespace LINE_HIGHLIGHT_CLASSES {
6601
6609
  let highlight: string;
6602
6610
  }
6603
6611
  /**
6604
- * Parse line highlight specifications from the code fence meta string.
6605
- *
6606
- * A remark plugin preserves the meta as a `data-meta` attribute on the <code>
6607
- * element. Components read it and pass it here as the `meta` parameter.
6612
+ * Parse line highlight specifications from a meta string.
6608
6613
  *
6609
- * Syntax (in meta string): `highlight="+1-3,-5,7"`
6614
+ * Syntax: `highlight="+1-3,-5,7"`
6610
6615
  * - `+` prefix: addition (green)
6611
6616
  * - `-` prefix: removal (red)
6612
6617
  * - no prefix: neutral highlight (blue)
@@ -6614,7 +6619,7 @@ export namespace LINE_HIGHLIGHT_CLASSES {
6614
6619
  * - comma-separated for multiple specs
6615
6620
  *
6616
6621
  * @param {string} languageString - the language, e.g. "javascript"
6617
- * @param {string} [meta] - the code fence meta string, e.g. 'highlight="+1-3,-5,7"'
6622
+ * @param {string} [meta] - string containing highlight specs, e.g. 'highlight="+1-3,-5,7"'
6618
6623
  * @returns {{ lang: string, highlights: Record<number, 'addition' | 'removal' | 'highlight'> }}
6619
6624
  */
6620
6625
  export function parseLineHighlights(languageString: string, meta?: string): {
@@ -6633,6 +6638,11 @@ export function splitHtmlLines(html: string): string[];
6633
6638
  //# sourceMappingURL=syntax-highlighter.d.ts.map
6634
6639
  }
6635
6640
 
6641
+ declare module '@ably/ui/core/utils/syntax-highlighter.test' {
6642
+ export {};
6643
+ //# sourceMappingURL=syntax-highlighter.test.d.ts.map
6644
+ }
6645
+
6636
6646
  declare module '@ably/ui/reset/scripts' {
6637
6647
  export {};
6638
6648
  //# sourceMappingURL=scripts.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ably/ui",
3
- "version": "17.14.0-dev.2fa7246503",
3
+ "version": "17.14.0-dev.65b2d6dd35",
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",
@@ -52,7 +52,7 @@
52
52
  "eslint-plugin-storybook": "^10.2.0",
53
53
  "heroicons": "^2.2.0",
54
54
  "http-server": "14.1.1",
55
- "jsdom": "^27.4.0",
55
+ "jsdom": "^28.0.0",
56
56
  "mixpanel-browser": "^2.74.0",
57
57
  "msw": "2.12.0",
58
58
  "msw-storybook-addon": "^2.0.5",