@ably/ui 18.3.2 → 18.4.1

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.
@@ -1,2 +1,2 @@
1
- import React from"react";import Accordion from"../Accordion";import{menuItemLinks}from"./data";import cn from"../utils/cn";export const MeganavMobile=({navItems})=>{const menuItemClassname="text-[18px] py-3 font-bold text-neutral-1000 dark:text-neutral-000 hover:text-neutral-1000 dark:hover:text-neutral-000 active:text-neutral-1000 dark:active:text-neutral-000";return React.createElement("div",{className:"overflow-y-auto"},React.createElement(Accordion,{theme:"transparent",className:"px-4 pt-4",data:navItems,icons:{closed:{name:"icon-gui-chevron-down-outline"},open:{name:"icon-gui-chevron-up-outline"}},options:{autoClose:true,hideBorders:true,headerCSS:`px-0 ${menuItemClassname}`,contentCSS:"px-0",selectedHeaderCSS:"text-neutral-1300 dark:text-neutral-000",rowIconSize:"24px"}}),menuItemLinks&&React.createElement("div",{className:"mb-3"},menuItemLinks.map(link=>React.createElement("a",{href:link.link,key:link.name,className:cn("px-4 w-full block ui-text-p1",menuItemClassname)},link.name))))};
1
+ import React from"react";import Accordion from"../Accordion";import{menuItemLinks}from"./data";import cn from"../utils/cn";export const MeganavMobile=({navItems})=>{const menuItemClassname="text-[18px] py-3 font-semibold text-neutral-1000 dark:text-neutral-000 hover:text-neutral-1000 dark:hover:text-neutral-000 active:text-neutral-1000 dark:active:text-neutral-000";return React.createElement("div",{className:"overflow-y-auto"},React.createElement(Accordion,{theme:"transparent",className:"px-4 pt-4",data:navItems,icons:{closed:{name:"icon-gui-chevron-down-outline"},open:{name:"icon-gui-chevron-up-outline"}},options:{autoClose:true,hideBorders:true,headerCSS:`px-0 ${menuItemClassname}`,contentCSS:"px-0",selectedHeaderCSS:"text-neutral-1300 dark:text-neutral-000",rowIconSize:"24px"}}),menuItemLinks&&React.createElement("div",{className:"mb-3"},menuItemLinks.map(link=>React.createElement("a",{href:link.link,key:link.name,className:cn("px-4 w-full block ui-text-p1",menuItemClassname)},link.name))))};
2
2
  //# sourceMappingURL=MeganavMobile.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/Meganav/MeganavMobile.tsx"],"sourcesContent":["import React from \"react\";\nimport Accordion from \"../Accordion\";\nimport { AccordionData } from \"../Accordion/types\";\nimport { menuItemLinks } from \"./data\";\nimport cn from \"../utils/cn\";\n\nexport const MeganavMobile = ({ navItems }: { navItems: AccordionData[] }) => {\n const menuItemClassname =\n \"text-[18px] py-3 font-bold text-neutral-1000 dark:text-neutral-000 hover:text-neutral-1000 dark:hover:text-neutral-000 active:text-neutral-1000 dark:active:text-neutral-000\";\n return (\n <div className=\"overflow-y-auto\">\n <Accordion\n theme=\"transparent\"\n className=\"px-4 pt-4\"\n data={navItems}\n icons={{\n closed: { name: \"icon-gui-chevron-down-outline\" },\n open: { name: \"icon-gui-chevron-up-outline\" },\n }}\n options={{\n autoClose: true,\n hideBorders: true,\n headerCSS: `px-0 ${menuItemClassname}`,\n contentCSS: \"px-0\",\n selectedHeaderCSS: \"text-neutral-1300 dark:text-neutral-000\",\n rowIconSize: \"24px\",\n }}\n />\n {menuItemLinks && (\n <div className=\"mb-3\">\n {menuItemLinks.map((link) => (\n <a\n href={link.link}\n key={link.name}\n className={cn(\"px-4 w-full block ui-text-p1\", menuItemClassname)}\n >\n {link.name}\n </a>\n ))}\n </div>\n )}\n </div>\n );\n};\n"],"names":["React","Accordion","menuItemLinks","cn","MeganavMobile","navItems","menuItemClassname","div","className","theme","data","icons","closed","name","open","options","autoClose","hideBorders","headerCSS","contentCSS","selectedHeaderCSS","rowIconSize","map","link","a","href","key"],"mappings":"AAAA,OAAOA,UAAW,OAAQ,AAC1B,QAAOC,cAAe,cAAe,AAErC,QAASC,aAAa,KAAQ,QAAS,AACvC,QAAOC,OAAQ,aAAc,AAE7B,QAAO,MAAMC,cAAgB,CAAC,CAAEC,QAAQ,CAAiC,IACvE,MAAMC,kBACJ,+KACF,OACE,oBAACC,OAAIC,UAAU,mBACb,oBAACP,WACCQ,MAAM,cACND,UAAU,YACVE,KAAML,SACNM,MAAO,CACLC,OAAQ,CAAEC,KAAM,+BAAgC,EAChDC,KAAM,CAAED,KAAM,6BAA8B,CAC9C,EACAE,QAAS,CACPC,UAAW,KACXC,YAAa,KACbC,UAAW,CAAC,KAAK,EAAEZ,kBAAkB,CAAC,CACtCa,WAAY,OACZC,kBAAmB,0CACnBC,YAAa,MACf,IAEDnB,eACC,oBAACK,OAAIC,UAAU,QACZN,cAAcoB,GAAG,CAAC,AAACC,MAClB,oBAACC,KACCC,KAAMF,KAAKA,IAAI,CACfG,IAAKH,KAAKV,IAAI,CACdL,UAAWL,GAAG,+BAAgCG,oBAE7CiB,KAAKV,IAAI,IAOxB,CAAE"}
1
+ {"version":3,"sources":["../../../src/core/Meganav/MeganavMobile.tsx"],"sourcesContent":["import React from \"react\";\nimport Accordion from \"../Accordion\";\nimport { AccordionData } from \"../Accordion/types\";\nimport { menuItemLinks } from \"./data\";\nimport cn from \"../utils/cn\";\n\nexport const MeganavMobile = ({ navItems }: { navItems: AccordionData[] }) => {\n const menuItemClassname =\n \"text-[18px] py-3 font-semibold text-neutral-1000 dark:text-neutral-000 hover:text-neutral-1000 dark:hover:text-neutral-000 active:text-neutral-1000 dark:active:text-neutral-000\";\n return (\n <div className=\"overflow-y-auto\">\n <Accordion\n theme=\"transparent\"\n className=\"px-4 pt-4\"\n data={navItems}\n icons={{\n closed: { name: \"icon-gui-chevron-down-outline\" },\n open: { name: \"icon-gui-chevron-up-outline\" },\n }}\n options={{\n autoClose: true,\n hideBorders: true,\n headerCSS: `px-0 ${menuItemClassname}`,\n contentCSS: \"px-0\",\n selectedHeaderCSS: \"text-neutral-1300 dark:text-neutral-000\",\n rowIconSize: \"24px\",\n }}\n />\n {menuItemLinks && (\n <div className=\"mb-3\">\n {menuItemLinks.map((link) => (\n <a\n href={link.link}\n key={link.name}\n className={cn(\"px-4 w-full block ui-text-p1\", menuItemClassname)}\n >\n {link.name}\n </a>\n ))}\n </div>\n )}\n </div>\n );\n};\n"],"names":["React","Accordion","menuItemLinks","cn","MeganavMobile","navItems","menuItemClassname","div","className","theme","data","icons","closed","name","open","options","autoClose","hideBorders","headerCSS","contentCSS","selectedHeaderCSS","rowIconSize","map","link","a","href","key"],"mappings":"AAAA,OAAOA,UAAW,OAAQ,AAC1B,QAAOC,cAAe,cAAe,AAErC,QAASC,aAAa,KAAQ,QAAS,AACvC,QAAOC,OAAQ,aAAc,AAE7B,QAAO,MAAMC,cAAgB,CAAC,CAAEC,QAAQ,CAAiC,IACvE,MAAMC,kBACJ,mLACF,OACE,oBAACC,OAAIC,UAAU,mBACb,oBAACP,WACCQ,MAAM,cACND,UAAU,YACVE,KAAML,SACNM,MAAO,CACLC,OAAQ,CAAEC,KAAM,+BAAgC,EAChDC,KAAM,CAAED,KAAM,6BAA8B,CAC9C,EACAE,QAAS,CACPC,UAAW,KACXC,YAAa,KACbC,UAAW,CAAC,KAAK,EAAEZ,kBAAkB,CAAC,CACtCa,WAAY,OACZC,kBAAmB,0CACnBC,YAAa,MACf,IAEDnB,eACC,oBAACK,OAAIC,UAAU,QACZN,cAAcoB,GAAG,CAAC,AAACC,MAClB,oBAACC,KACCC,KAAMF,KAAKA,IAAI,CACfG,IAAKH,KAAKV,IAAI,CACdL,UAAWL,GAAG,+BAAgCG,oBAE7CiB,KAAKV,IAAI,IAOxB,CAAE"}
package/core/Meganav.js CHANGED
@@ -1,2 +1,2 @@
1
- import React,{useEffect,useMemo}from"react";import Header from"./Header";import Flyout from"./Flyout";import{MeganavMobile}from"./Meganav/MeganavMobile";import Notice from"./Notice";import{HEADER_HEIGHT}from"./utils/heights";import{getMenuItemsForHeader}from"./Meganav/utils/getMenuItemsForHeader";const Meganav=({sessionState,notice,theme,themedScrollpoints,onNoticeClose,blogPosts})=>{const[noticeHeight,setNoticeHeight]=React.useState(0);const finalNoticeHeight=notice?noticeHeight:0;const headerMenuItems=useMemo(()=>getMenuItemsForHeader(blogPosts),[blogPosts]);const mobileNavItems=useMemo(()=>headerMenuItems.filter(item=>!item.isHiddenMobile).map(({name,link,content})=>({name,link,content})),[headerMenuItems]);const defaultThemedScrollpoints=[{id:"meganav",className:"ui-theme-light !bg-transparent !border-none"},{id:"meganav-theme-dark",className:"ui-theme-dark !bg-transparent !border-none"},{id:"main",className:"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b"},{id:"main-theme-dark",className:"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b"}];useEffect(()=>{if(!notice)return;const noticeElement=document.querySelector('[data-id="ui-notice"]');if(!noticeElement)return;const updateNoticeHeight=()=>{setNoticeHeight(noticeElement.getBoundingClientRect().height)};const observer=new ResizeObserver(updateNoticeHeight);observer.observe(noticeElement);const timeoutId=setTimeout(updateNoticeHeight,0);window.addEventListener("resize",updateNoticeHeight);return()=>{clearTimeout(timeoutId);observer.disconnect();window.removeEventListener("resize",updateNoticeHeight)}},[notice]);return React.createElement(React.Fragment,null,React.createElement("div",{className:"absolute top-0 left-0 right-0 w-full z-50",id:theme==="dark"?"meganav-theme-dark":"meganav","data-testid":"meganav",style:{height:HEADER_HEIGHT+finalNoticeHeight}},notice&&React.createElement(Notice,{...notice.props,config:notice.config,onClose:onNoticeClose}),React.createElement(Header,{className:"max-w-screen-xl mx-auto",isNoticeBannerEnabled:!!notice,noticeHeight:finalNoticeHeight,nav:React.createElement(Flyout,{menuItems:headerMenuItems,className:"justify-left z-40",flyOutClassName:"flex justify-left",viewPortClassName:"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300"}),mobileNav:React.createElement(MeganavMobile,{navItems:mobileNavItems}),headerLinks:[{href:"/contact",label:"Contact us"}],headerLinksClassName:"md:gap-x-6 ",sessionState:sessionState,themedScrollpoints:themedScrollpoints??defaultThemedScrollpoints})))};export default Meganav;
1
+ import React,{useEffect,useMemo}from"react";import Header from"./Header";import Flyout from"./Flyout";import{MeganavMobile}from"./Meganav/MeganavMobile";import Notice from"./Notice";import{HEADER_HEIGHT}from"./utils/heights";import{getMenuItemsForHeader}from"./Meganav/utils/getMenuItemsForHeader";const Meganav=({sessionState,notice,theme,themedScrollpoints,onNoticeClose,blogPosts})=>{const[noticeHeight,setNoticeHeight]=React.useState(0);const finalNoticeHeight=notice?noticeHeight:0;const headerMenuItems=useMemo(()=>getMenuItemsForHeader(blogPosts),[blogPosts]);const mobileNavItems=useMemo(()=>headerMenuItems.filter(item=>!item.isHiddenMobile).map(({name,link,content})=>({name,link,content})),[headerMenuItems]);const defaultThemedScrollpoints=[{id:"meganav",className:"ui-theme-light !bg-transparent !border-none"},{id:"meganav-theme-dark",className:"ui-theme-dark !bg-transparent !border-none"},{id:"main",className:"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b"},{id:"main-theme-dark",className:"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b"}];useEffect(()=>{if(!notice)return;const noticeElement=document.querySelector('[data-id="ui-notice"]');if(!noticeElement)return;const updateNoticeHeight=()=>{setNoticeHeight(noticeElement.getBoundingClientRect().height)};const observer=new ResizeObserver(updateNoticeHeight);observer.observe(noticeElement);const timeoutId=setTimeout(updateNoticeHeight,0);window.addEventListener("resize",updateNoticeHeight);return()=>{clearTimeout(timeoutId);observer.disconnect();window.removeEventListener("resize",updateNoticeHeight)}},[notice]);return React.createElement(React.Fragment,null,React.createElement("div",{className:"absolute top-0 left-0 right-0 w-full z-50",id:theme==="dark"?"meganav-theme-dark":"meganav","data-testid":"meganav",style:{height:HEADER_HEIGHT+finalNoticeHeight}},notice&&React.createElement(Notice,{...notice.props,config:notice.config,onClose:onNoticeClose}),React.createElement(Header,{className:"max-w-screen-xl mx-auto ui-grid-px",isNoticeBannerEnabled:!!notice,noticeHeight:finalNoticeHeight,nav:React.createElement(Flyout,{menuItems:headerMenuItems,className:"justify-left z-40",flyOutClassName:"flex justify-left",viewPortClassName:"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300"}),mobileNav:React.createElement(MeganavMobile,{navItems:mobileNavItems}),headerLinks:[{href:"/contact",label:"Contact us"}],headerLinksClassName:"md:gap-x-6 ",sessionState:sessionState,themedScrollpoints:themedScrollpoints??defaultThemedScrollpoints})))};export default Meganav;
2
2
  //# sourceMappingURL=Meganav.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/Meganav.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport Header, { HeaderSessionState, ThemedScrollpoint } from \"./Header\";\nimport Flyout from \"./Flyout\";\nimport { MeganavMobile } from \"./Meganav/MeganavMobile\";\nimport Notice from \"./Notice\";\nimport { HEADER_HEIGHT } from \"./utils/heights\";\nimport { BlogPost } from \"./Meganav/MeganavBlog\";\nimport { getMenuItemsForHeader } from \"./Meganav/utils/getMenuItemsForHeader\";\n\nexport type MeganavNoticeBannerProps = {\n props: {\n title: string;\n bodyText: string;\n buttonLink: string;\n buttonLabel: string;\n closeBtn: boolean;\n };\n config: {\n cookieId: string;\n noticeId: string | number;\n options: {\n collapse: boolean;\n };\n };\n};\n\nexport type MeganavProps = {\n sessionState: HeaderSessionState;\n blogPosts: BlogPost[];\n notice?: MeganavNoticeBannerProps;\n theme?: string;\n themedScrollpoints?: ThemedScrollpoint[];\n onNoticeClose?: () => void;\n};\n\nconst Meganav = ({\n sessionState,\n notice,\n theme,\n themedScrollpoints,\n onNoticeClose,\n blogPosts,\n}: MeganavProps) => {\n const [noticeHeight, setNoticeHeight] = React.useState(0);\n\n const finalNoticeHeight = notice ? noticeHeight : 0;\n\n const headerMenuItems = useMemo(\n () => getMenuItemsForHeader(blogPosts),\n [blogPosts],\n );\n\n const mobileNavItems = useMemo(\n () =>\n headerMenuItems\n .filter((item) => !item.isHiddenMobile)\n .map(({ name, link, content }) => ({ name, link, content })),\n [headerMenuItems],\n );\n\n const defaultThemedScrollpoints = [\n {\n id: \"meganav\",\n className: \"ui-theme-light !bg-transparent !border-none\",\n },\n {\n id: \"meganav-theme-dark\",\n className: \"ui-theme-dark !bg-transparent !border-none\",\n },\n {\n id: \"main\",\n className: \"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n {\n id: \"main-theme-dark\",\n className: \"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n ];\n\n useEffect(() => {\n if (!notice) return;\n\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n if (!noticeElement) return;\n\n const updateNoticeHeight = () => {\n setNoticeHeight(noticeElement.getBoundingClientRect().height);\n };\n\n const observer = new ResizeObserver(updateNoticeHeight);\n observer.observe(noticeElement);\n\n const timeoutId = setTimeout(updateNoticeHeight, 0);\n window.addEventListener(\"resize\", updateNoticeHeight);\n\n return () => {\n clearTimeout(timeoutId);\n observer.disconnect();\n window.removeEventListener(\"resize\", updateNoticeHeight);\n };\n }, [notice]);\n\n return (\n <>\n <div\n className=\"absolute top-0 left-0 right-0 w-full z-50\"\n id={theme === \"dark\" ? \"meganav-theme-dark\" : \"meganav\"}\n data-testid=\"meganav\"\n style={{ height: HEADER_HEIGHT + finalNoticeHeight }}\n >\n {notice && (\n <Notice\n {...notice.props}\n config={notice.config}\n onClose={onNoticeClose}\n />\n )}\n <Header\n className=\"max-w-screen-xl mx-auto\"\n isNoticeBannerEnabled={!!notice}\n noticeHeight={finalNoticeHeight}\n nav={\n <Flyout\n menuItems={headerMenuItems}\n className=\"justify-left z-40\"\n flyOutClassName=\"flex justify-left\"\n viewPortClassName=\"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300\"\n />\n }\n mobileNav={<MeganavMobile navItems={mobileNavItems} />}\n headerLinks={[{ href: \"/contact\", label: \"Contact us\" }]}\n headerLinksClassName=\"md:gap-x-6 \"\n sessionState={sessionState}\n themedScrollpoints={themedScrollpoints ?? defaultThemedScrollpoints}\n />\n </div>\n </>\n );\n};\n\nexport default Meganav;\n"],"names":["React","useEffect","useMemo","Header","Flyout","MeganavMobile","Notice","HEADER_HEIGHT","getMenuItemsForHeader","Meganav","sessionState","notice","theme","themedScrollpoints","onNoticeClose","blogPosts","noticeHeight","setNoticeHeight","useState","finalNoticeHeight","headerMenuItems","mobileNavItems","filter","item","isHiddenMobile","map","name","link","content","defaultThemedScrollpoints","id","className","noticeElement","document","querySelector","updateNoticeHeight","getBoundingClientRect","height","observer","ResizeObserver","observe","timeoutId","setTimeout","window","addEventListener","clearTimeout","disconnect","removeEventListener","div","data-testid","style","props","config","onClose","isNoticeBannerEnabled","nav","menuItems","flyOutClassName","viewPortClassName","mobileNav","navItems","headerLinks","href","label","headerLinksClassName"],"mappings":"AAAA,OAAOA,OAASC,SAAS,CAAEC,OAAO,KAAQ,OAAQ,AAClD,QAAOC,WAAuD,UAAW,AACzE,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,yBAA0B,AACxD,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,iBAAkB,AAEhD,QAASC,qBAAqB,KAAQ,uCAAwC,CA4B9E,MAAMC,QAAU,CAAC,CACfC,YAAY,CACZC,MAAM,CACNC,KAAK,CACLC,kBAAkB,CAClBC,aAAa,CACbC,SAAS,CACI,IACb,KAAM,CAACC,aAAcC,gBAAgB,CAAGjB,MAAMkB,QAAQ,CAAC,GAEvD,MAAMC,kBAAoBR,OAASK,aAAe,EAElD,MAAMI,gBAAkBlB,QACtB,IAAMM,sBAAsBO,WAC5B,CAACA,UAAU,EAGb,MAAMM,eAAiBnB,QACrB,IACEkB,gBACGE,MAAM,CAAC,AAACC,MAAS,CAACA,KAAKC,cAAc,EACrCC,GAAG,CAAC,CAAC,CAAEC,IAAI,CAAEC,IAAI,CAAEC,OAAO,CAAE,GAAM,CAAA,CAAEF,KAAMC,KAAMC,OAAQ,CAAA,GAC7D,CAACR,gBAAgB,EAGnB,MAAMS,0BAA4B,CAChC,CACEC,GAAI,UACJC,UAAW,6CACb,EACA,CACED,GAAI,qBACJC,UAAW,4CACb,EACA,CACED,GAAI,OACJC,UAAW,6DACb,EACA,CACED,GAAI,kBACJC,UAAW,4DACb,EACD,CAED9B,UAAU,KACR,GAAI,CAACU,OAAQ,OAEb,MAAMqB,cAAgBC,SAASC,aAAa,CAAC,yBAC7C,GAAI,CAACF,cAAe,OAEpB,MAAMG,mBAAqB,KACzBlB,gBAAgBe,cAAcI,qBAAqB,GAAGC,MAAM,CAC9D,EAEA,MAAMC,SAAW,IAAIC,eAAeJ,oBACpCG,SAASE,OAAO,CAACR,eAEjB,MAAMS,UAAYC,WAAWP,mBAAoB,GACjDQ,OAAOC,gBAAgB,CAAC,SAAUT,oBAElC,MAAO,KACLU,aAAaJ,WACbH,SAASQ,UAAU,GACnBH,OAAOI,mBAAmB,CAAC,SAAUZ,mBACvC,CACF,EAAG,CAACxB,OAAO,EAEX,OACE,wCACE,oBAACqC,OACCjB,UAAU,4CACVD,GAAIlB,QAAU,OAAS,qBAAuB,UAC9CqC,cAAY,UACZC,MAAO,CAAEb,OAAQ9B,cAAgBY,iBAAkB,GAElDR,QACC,oBAACL,QACE,GAAGK,OAAOwC,KAAK,CAChBC,OAAQzC,OAAOyC,MAAM,CACrBC,QAASvC,gBAGb,oBAACX,QACC4B,UAAU,0BACVuB,sBAAuB,CAAC,CAAC3C,OACzBK,aAAcG,kBACdoC,IACE,oBAACnD,QACCoD,UAAWpC,gBACXW,UAAU,oBACV0B,gBAAgB,oBAChBC,kBAAkB,iIAGtBC,UAAW,oBAACtD,eAAcuD,SAAUvC,iBACpCwC,YAAa,CAAC,CAAEC,KAAM,WAAYC,MAAO,YAAa,EAAE,CACxDC,qBAAqB,cACrBtD,aAAcA,aACdG,mBAAoBA,oBAAsBgB,6BAKpD,CAEA,gBAAepB,OAAQ"}
1
+ {"version":3,"sources":["../../src/core/Meganav.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport Header, { HeaderSessionState, ThemedScrollpoint } from \"./Header\";\nimport Flyout from \"./Flyout\";\nimport { MeganavMobile } from \"./Meganav/MeganavMobile\";\nimport Notice from \"./Notice\";\nimport { HEADER_HEIGHT } from \"./utils/heights\";\nimport { BlogPost } from \"./Meganav/MeganavBlog\";\nimport { getMenuItemsForHeader } from \"./Meganav/utils/getMenuItemsForHeader\";\n\nexport type MeganavNoticeBannerProps = {\n props: {\n title: string;\n bodyText: string;\n buttonLink: string;\n buttonLabel: string;\n closeBtn: boolean;\n };\n config: {\n cookieId: string;\n noticeId: string | number;\n options: {\n collapse: boolean;\n };\n };\n};\n\nexport type MeganavProps = {\n sessionState: HeaderSessionState;\n blogPosts: BlogPost[];\n notice?: MeganavNoticeBannerProps;\n theme?: string;\n themedScrollpoints?: ThemedScrollpoint[];\n onNoticeClose?: () => void;\n};\n\nconst Meganav = ({\n sessionState,\n notice,\n theme,\n themedScrollpoints,\n onNoticeClose,\n blogPosts,\n}: MeganavProps) => {\n const [noticeHeight, setNoticeHeight] = React.useState(0);\n\n const finalNoticeHeight = notice ? noticeHeight : 0;\n\n const headerMenuItems = useMemo(\n () => getMenuItemsForHeader(blogPosts),\n [blogPosts],\n );\n\n const mobileNavItems = useMemo(\n () =>\n headerMenuItems\n .filter((item) => !item.isHiddenMobile)\n .map(({ name, link, content }) => ({ name, link, content })),\n [headerMenuItems],\n );\n\n const defaultThemedScrollpoints = [\n {\n id: \"meganav\",\n className: \"ui-theme-light !bg-transparent !border-none\",\n },\n {\n id: \"meganav-theme-dark\",\n className: \"ui-theme-dark !bg-transparent !border-none\",\n },\n {\n id: \"main\",\n className: \"ui-theme-light bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n {\n id: \"main-theme-dark\",\n className: \"ui-theme-dark bg-neutral-000 dark:bg-neutral-1300 border-b\",\n },\n ];\n\n useEffect(() => {\n if (!notice) return;\n\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n if (!noticeElement) return;\n\n const updateNoticeHeight = () => {\n setNoticeHeight(noticeElement.getBoundingClientRect().height);\n };\n\n const observer = new ResizeObserver(updateNoticeHeight);\n observer.observe(noticeElement);\n\n const timeoutId = setTimeout(updateNoticeHeight, 0);\n window.addEventListener(\"resize\", updateNoticeHeight);\n\n return () => {\n clearTimeout(timeoutId);\n observer.disconnect();\n window.removeEventListener(\"resize\", updateNoticeHeight);\n };\n }, [notice]);\n\n return (\n <>\n <div\n className=\"absolute top-0 left-0 right-0 w-full z-50\"\n id={theme === \"dark\" ? \"meganav-theme-dark\" : \"meganav\"}\n data-testid=\"meganav\"\n style={{ height: HEADER_HEIGHT + finalNoticeHeight }}\n >\n {notice && (\n <Notice\n {...notice.props}\n config={notice.config}\n onClose={onNoticeClose}\n />\n )}\n <Header\n className=\"max-w-screen-xl mx-auto ui-grid-px\"\n isNoticeBannerEnabled={!!notice}\n noticeHeight={finalNoticeHeight}\n nav={\n <Flyout\n menuItems={headerMenuItems}\n className=\"justify-left z-40\"\n flyOutClassName=\"flex justify-left\"\n viewPortClassName=\"ui-shadow-lg-medium border border-neutral-200 dark:border-neutral-1100 rounded-2xl -mt-1 bg-neutral-000 dark:bg-neutral-1300\"\n />\n }\n mobileNav={<MeganavMobile navItems={mobileNavItems} />}\n headerLinks={[{ href: \"/contact\", label: \"Contact us\" }]}\n headerLinksClassName=\"md:gap-x-6 \"\n sessionState={sessionState}\n themedScrollpoints={themedScrollpoints ?? defaultThemedScrollpoints}\n />\n </div>\n </>\n );\n};\n\nexport default Meganav;\n"],"names":["React","useEffect","useMemo","Header","Flyout","MeganavMobile","Notice","HEADER_HEIGHT","getMenuItemsForHeader","Meganav","sessionState","notice","theme","themedScrollpoints","onNoticeClose","blogPosts","noticeHeight","setNoticeHeight","useState","finalNoticeHeight","headerMenuItems","mobileNavItems","filter","item","isHiddenMobile","map","name","link","content","defaultThemedScrollpoints","id","className","noticeElement","document","querySelector","updateNoticeHeight","getBoundingClientRect","height","observer","ResizeObserver","observe","timeoutId","setTimeout","window","addEventListener","clearTimeout","disconnect","removeEventListener","div","data-testid","style","props","config","onClose","isNoticeBannerEnabled","nav","menuItems","flyOutClassName","viewPortClassName","mobileNav","navItems","headerLinks","href","label","headerLinksClassName"],"mappings":"AAAA,OAAOA,OAASC,SAAS,CAAEC,OAAO,KAAQ,OAAQ,AAClD,QAAOC,WAAuD,UAAW,AACzE,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,yBAA0B,AACxD,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,iBAAkB,AAEhD,QAASC,qBAAqB,KAAQ,uCAAwC,CA4B9E,MAAMC,QAAU,CAAC,CACfC,YAAY,CACZC,MAAM,CACNC,KAAK,CACLC,kBAAkB,CAClBC,aAAa,CACbC,SAAS,CACI,IACb,KAAM,CAACC,aAAcC,gBAAgB,CAAGjB,MAAMkB,QAAQ,CAAC,GAEvD,MAAMC,kBAAoBR,OAASK,aAAe,EAElD,MAAMI,gBAAkBlB,QACtB,IAAMM,sBAAsBO,WAC5B,CAACA,UAAU,EAGb,MAAMM,eAAiBnB,QACrB,IACEkB,gBACGE,MAAM,CAAC,AAACC,MAAS,CAACA,KAAKC,cAAc,EACrCC,GAAG,CAAC,CAAC,CAAEC,IAAI,CAAEC,IAAI,CAAEC,OAAO,CAAE,GAAM,CAAA,CAAEF,KAAMC,KAAMC,OAAQ,CAAA,GAC7D,CAACR,gBAAgB,EAGnB,MAAMS,0BAA4B,CAChC,CACEC,GAAI,UACJC,UAAW,6CACb,EACA,CACED,GAAI,qBACJC,UAAW,4CACb,EACA,CACED,GAAI,OACJC,UAAW,6DACb,EACA,CACED,GAAI,kBACJC,UAAW,4DACb,EACD,CAED9B,UAAU,KACR,GAAI,CAACU,OAAQ,OAEb,MAAMqB,cAAgBC,SAASC,aAAa,CAAC,yBAC7C,GAAI,CAACF,cAAe,OAEpB,MAAMG,mBAAqB,KACzBlB,gBAAgBe,cAAcI,qBAAqB,GAAGC,MAAM,CAC9D,EAEA,MAAMC,SAAW,IAAIC,eAAeJ,oBACpCG,SAASE,OAAO,CAACR,eAEjB,MAAMS,UAAYC,WAAWP,mBAAoB,GACjDQ,OAAOC,gBAAgB,CAAC,SAAUT,oBAElC,MAAO,KACLU,aAAaJ,WACbH,SAASQ,UAAU,GACnBH,OAAOI,mBAAmB,CAAC,SAAUZ,mBACvC,CACF,EAAG,CAACxB,OAAO,EAEX,OACE,wCACE,oBAACqC,OACCjB,UAAU,4CACVD,GAAIlB,QAAU,OAAS,qBAAuB,UAC9CqC,cAAY,UACZC,MAAO,CAAEb,OAAQ9B,cAAgBY,iBAAkB,GAElDR,QACC,oBAACL,QACE,GAAGK,OAAOwC,KAAK,CAChBC,OAAQzC,OAAOyC,MAAM,CACrBC,QAASvC,gBAGb,oBAACX,QACC4B,UAAU,qCACVuB,sBAAuB,CAAC,CAAC3C,OACzBK,aAAcG,kBACdoC,IACE,oBAACnD,QACCoD,UAAWpC,gBACXW,UAAU,oBACV0B,gBAAgB,oBAChBC,kBAAkB,iIAGtBC,UAAW,oBAACtD,eAAcuD,SAAUvC,iBACpCwC,YAAa,CAAC,CAAEC,KAAM,WAAYC,MAAO,YAAa,EAAE,CACxDC,qBAAqB,cACrBtD,aAAcA,aACdG,mBAAoBA,oBAAsBgB,6BAKpD,CAEA,gBAAepB,OAAQ"}
package/core/TabMenu.js CHANGED
@@ -1,2 +1,2 @@
1
- import React,{useEffect}from"react";import*as Tabs from"@radix-ui/react-tabs";import{throttle}from"es-toolkit/compat";import cn from"./utils/cn";const DEFAULT_TAILWIND_ANIMATION_DURATION=150;const TabMenu=({tabs=[],contents=[],tabOnClick,tabClassName,rootClassName,contentClassName,options})=>{const{defaultTabIndex=0,underline=true,animated:animatedOption=true,flexibleTabWidth=false,flexibleTabHeight=false}=options??{};const listRef=React.useRef(null);const[animated,setAnimated]=React.useState(false);const[highlight,setHighlight]=React.useState({offset:0,width:0});useEffect(()=>{if(animatedOption&&highlight.width>0){setTimeout(()=>{setAnimated(true)},DEFAULT_TAILWIND_ANIMATION_DURATION)}},[animatedOption,highlight.width]);const updateHighlightDimensions=element=>{const{left:parentLeft}=listRef.current?.getBoundingClientRect()??{};const{left,width}=element.getBoundingClientRect()??{};setHighlight({offset:(left??0)-(parentLeft??0),width:width??0})};useEffect(()=>{const handleResize=throttle(()=>{const activeTabElement=listRef.current?.querySelector(`[data-state="active"]`);if(activeTabElement){updateHighlightDimensions(activeTabElement)}},100);handleResize();window.addEventListener("resize",handleResize);return()=>{window.removeEventListener("resize",handleResize)}},[]);const handleTabClick=(event,index)=>{tabOnClick?.(index);updateHighlightDimensions(event.currentTarget)};const tabTriggerContent=tab=>{if(!tab){return null}if(React.isValidElement(tab)||typeof tab==="string"){return tab}if(typeof tab==="object"&&"label"in tab){return tab.label}return null};return React.createElement(Tabs.Root,{defaultValue:`tab-${defaultTabIndex}`,className:cn({"h-full":flexibleTabHeight},rootClassName)},React.createElement(Tabs.List,{ref:listRef,className:cn("relative",{"flex border-b border-neutral-300 dark:border-neutral-1000":underline},{"h-full":flexibleTabHeight})},tabs.map((tab,index)=>tab&&React.createElement(Tabs.Trigger,{key:`tab-${index}`,className:cn("lg:px-6 md:px-5 px-4 py-4 ui-text-label1 font-bold data-[state=active]:text-neutral-1300 text-neutral-1000 dark:data-[state=active]:text-neutral-000 dark:text-neutral-300 focus:outline-none focus-visible:outline-gui-focus transition-colors hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-900 dark:active:text-neutral-400 disabled:text-gui-disabled-light dark:disabled:text-gui-disabled-dark disabled:cursor-not-allowed",{"flex-1":flexibleTabWidth},{"h-full":flexibleTabHeight},tabClassName),value:`tab-${index}`,onClick:event=>handleTabClick(event,index),disabled:typeof tab==="object"&&"disabled"in tab?tab.disabled:false},tabTriggerContent(tab))),React.createElement("div",{className:cn("absolute bottom-0 bg-neutral-1300 dark:bg-neutral-000 h-[0.1875rem] w-6",{"transition-[transform,width]":animated}),style:{transform:`translateX(${highlight.offset}px)`,width:`${highlight.width}px`}})),contents.map((content,index)=>React.createElement(Tabs.Content,{key:`tab-${index}`,value:`tab-${index}`,className:contentClassName},content)))};export default TabMenu;
1
+ import React,{useEffect}from"react";import*as Tabs from"@radix-ui/react-tabs";import{throttle}from"es-toolkit/compat";import cn from"./utils/cn";const DEFAULT_TAILWIND_ANIMATION_DURATION=150;const TabMenu=({tabs=[],contents=[],tabOnClick,tabClassName,rootClassName,contentClassName,options})=>{const{defaultTabIndex=0,underline=true,animated:animatedOption=true,flexibleTabWidth=false,flexibleTabHeight=false}=options??{};const listRef=React.useRef(null);const[animated,setAnimated]=React.useState(false);const[highlight,setHighlight]=React.useState({offset:0,width:0});useEffect(()=>{if(animatedOption&&highlight.width>0){setTimeout(()=>{setAnimated(true)},DEFAULT_TAILWIND_ANIMATION_DURATION)}},[animatedOption,highlight.width]);const updateHighlightDimensions=element=>{const{left:parentLeft}=listRef.current?.getBoundingClientRect()??{};const{left,width}=element.getBoundingClientRect()??{};setHighlight({offset:(left??0)-(parentLeft??0),width:width??0})};useEffect(()=>{const handleResize=throttle(()=>{const activeTabElement=listRef.current?.querySelector(`[data-state="active"]`);if(activeTabElement){updateHighlightDimensions(activeTabElement)}},100);handleResize();window.addEventListener("resize",handleResize);return()=>{window.removeEventListener("resize",handleResize)}},[]);const handleTabClick=(event,index)=>{tabOnClick?.(index);updateHighlightDimensions(event.currentTarget)};const tabTriggerContent=tab=>{if(!tab){return null}if(React.isValidElement(tab)||typeof tab==="string"){return tab}if(typeof tab==="object"&&"label"in tab){return tab.label}return null};return React.createElement(Tabs.Root,{defaultValue:`tab-${defaultTabIndex}`,className:cn({"h-full":flexibleTabHeight},rootClassName)},React.createElement(Tabs.List,{ref:listRef,className:cn("relative",{"flex border-b border-neutral-300 dark:border-neutral-1000":underline},{"h-full":flexibleTabHeight})},tabs.map((tab,index)=>tab&&React.createElement(Tabs.Trigger,{key:`tab-${index}`,className:cn("lg:px-6 md:px-5 px-4 py-4 ui-text-label1 font-semibold data-[state=active]:text-neutral-1300 text-neutral-1000 dark:data-[state=active]:text-neutral-000 dark:text-neutral-300 focus:outline-none focus-visible:outline-gui-focus transition-colors hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-900 dark:active:text-neutral-400 disabled:text-gui-disabled-light dark:disabled:text-gui-disabled-dark disabled:cursor-not-allowed",{"flex-1":flexibleTabWidth},{"h-full":flexibleTabHeight},tabClassName),value:`tab-${index}`,onClick:event=>handleTabClick(event,index),disabled:typeof tab==="object"&&"disabled"in tab?tab.disabled:false},tabTriggerContent(tab))),React.createElement("div",{className:cn("absolute bottom-0 bg-neutral-1300 dark:bg-neutral-000 h-[0.1875rem] w-6",{"transition-[transform,width]":animated}),style:{transform:`translateX(${highlight.offset}px)`,width:`${highlight.width}px`}})),contents.map((content,index)=>React.createElement(Tabs.Content,{key:`tab-${index}`,value:`tab-${index}`,className:contentClassName},content)))};export default TabMenu;
2
2
  //# sourceMappingURL=TabMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/TabMenu.tsx"],"sourcesContent":["import React, { ReactNode, useEffect } from \"react\";\nimport * as Tabs from \"@radix-ui/react-tabs\";\nimport { throttle } from \"es-toolkit/compat\";\nimport cn from \"./utils/cn\";\n\ntype TabTriggerContent =\n | string\n | { label: string; disabled?: boolean }\n | ReactNode;\n\n/**\n * Props for the TabMenu component.\n */\n\nexport type TabMenuProps = {\n /**\n * An array of tabs, which can be either a string or an object with a label and an optional disabled state.\n */\n tabs: TabTriggerContent[];\n\n /**\n * An optional array of React nodes representing the content for each tab.\n */\n contents?: ReactNode[];\n\n /**\n * An optional callback function that is called when a tab is clicked, receiving the index of the clicked tab.\n */\n tabOnClick?: (index: number) => void;\n\n /**\n * An optional class name to apply to each tab.\n */\n tabClassName?: string;\n\n /**\n * An optional class name to apply to the Tabs.Root element.\n */\n rootClassName?: string;\n\n /**\n * An optional class name to apply to the Tabs.Content element.\n */\n contentClassName?: string;\n\n /**\n * Optional configuration options for the TabMenu.\n */\n options?: {\n /**\n * The index of the tab that should be selected by default.\n */\n defaultTabIndex?: number;\n\n /**\n * Whether to show an underline below the selected tab.\n */\n underline?: boolean;\n\n /**\n * Whether to animate the transition between tabs.\n */\n animated?: boolean;\n\n /**\n * Whether the tab width should be flexible.\n */\n flexibleTabWidth?: boolean;\n\n /**\n * Whether the tab height should be flexible.\n */\n flexibleTabHeight?: boolean;\n };\n};\n\nconst DEFAULT_TAILWIND_ANIMATION_DURATION = 150;\n\nconst TabMenu: React.FC<TabMenuProps> = ({\n tabs = [],\n contents = [],\n tabOnClick,\n tabClassName,\n rootClassName,\n contentClassName,\n options,\n}) => {\n const {\n defaultTabIndex = 0,\n underline = true,\n animated: animatedOption = true,\n flexibleTabWidth = false,\n flexibleTabHeight = false,\n } = options ?? {};\n\n const listRef = React.useRef<HTMLDivElement>(null);\n const [animated, setAnimated] = React.useState(false);\n const [highlight, setHighlight] = React.useState({ offset: 0, width: 0 });\n\n useEffect(() => {\n if (animatedOption && highlight.width > 0) {\n setTimeout(() => {\n setAnimated(true);\n }, DEFAULT_TAILWIND_ANIMATION_DURATION);\n }\n }, [animatedOption, highlight.width]);\n\n const updateHighlightDimensions = (element: HTMLButtonElement) => {\n const { left: parentLeft } = listRef.current?.getBoundingClientRect() ?? {};\n const { left, width } = element.getBoundingClientRect() ?? {};\n\n setHighlight({\n offset: (left ?? 0) - (parentLeft ?? 0),\n width: width ?? 0,\n });\n };\n\n useEffect(() => {\n const handleResize = throttle(() => {\n const activeTabElement =\n listRef.current?.querySelector<HTMLButtonElement>(\n `[data-state=\"active\"]`,\n );\n\n if (activeTabElement) {\n updateHighlightDimensions(activeTabElement);\n }\n }, 100);\n\n handleResize();\n\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }, []);\n\n const handleTabClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n index: number,\n ) => {\n tabOnClick?.(index);\n updateHighlightDimensions(event.currentTarget as HTMLButtonElement);\n };\n\n const tabTriggerContent = (tab: TabTriggerContent) => {\n if (!tab) {\n return null;\n }\n\n if (React.isValidElement(tab) || typeof tab === \"string\") {\n return tab;\n }\n\n if (typeof tab === \"object\" && \"label\" in tab) {\n return tab.label;\n }\n\n return null;\n };\n\n return (\n <Tabs.Root\n defaultValue={`tab-${defaultTabIndex}`}\n className={cn({ \"h-full\": flexibleTabHeight }, rootClassName)}\n >\n <Tabs.List\n ref={listRef}\n className={cn(\n \"relative\",\n {\n \"flex border-b border-neutral-300 dark:border-neutral-1000\":\n underline,\n },\n { \"h-full\": flexibleTabHeight },\n )}\n >\n {tabs.map(\n (tab, index) =>\n tab && (\n <Tabs.Trigger\n key={`tab-${index}`}\n className={cn(\n \"lg:px-6 md:px-5 px-4 py-4 ui-text-label1 font-bold data-[state=active]:text-neutral-1300 text-neutral-1000 dark:data-[state=active]:text-neutral-000 dark:text-neutral-300 focus:outline-none focus-visible:outline-gui-focus transition-colors hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-900 dark:active:text-neutral-400 disabled:text-gui-disabled-light dark:disabled:text-gui-disabled-dark disabled:cursor-not-allowed\",\n { \"flex-1\": flexibleTabWidth },\n { \"h-full\": flexibleTabHeight },\n tabClassName,\n )}\n value={`tab-${index}`}\n onClick={(event) => handleTabClick(event, index)}\n disabled={\n typeof tab === \"object\" && \"disabled\" in tab\n ? tab.disabled\n : false\n }\n >\n {tabTriggerContent(tab)}\n </Tabs.Trigger>\n ),\n )}\n <div\n className={cn(\n \"absolute bottom-0 bg-neutral-1300 dark:bg-neutral-000 h-[0.1875rem] w-6\",\n { \"transition-[transform,width]\": animated },\n )}\n style={{\n transform: `translateX(${highlight.offset}px)`,\n width: `${highlight.width}px`,\n }}\n ></div>\n </Tabs.List>\n {contents.map((content, index) => (\n <Tabs.Content\n key={`tab-${index}`}\n value={`tab-${index}`}\n className={contentClassName}\n >\n {content}\n </Tabs.Content>\n ))}\n </Tabs.Root>\n );\n};\n\nexport default TabMenu;\n"],"names":["React","useEffect","Tabs","throttle","cn","DEFAULT_TAILWIND_ANIMATION_DURATION","TabMenu","tabs","contents","tabOnClick","tabClassName","rootClassName","contentClassName","options","defaultTabIndex","underline","animated","animatedOption","flexibleTabWidth","flexibleTabHeight","listRef","useRef","setAnimated","useState","highlight","setHighlight","offset","width","setTimeout","updateHighlightDimensions","element","left","parentLeft","current","getBoundingClientRect","handleResize","activeTabElement","querySelector","window","addEventListener","removeEventListener","handleTabClick","event","index","currentTarget","tabTriggerContent","tab","isValidElement","label","Root","defaultValue","className","List","ref","map","Trigger","key","value","onClick","disabled","div","style","transform","content","Content"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/TabMenu.tsx"],"sourcesContent":["import React, { ReactNode, useEffect } from \"react\";\nimport * as Tabs from \"@radix-ui/react-tabs\";\nimport { throttle } from \"es-toolkit/compat\";\nimport cn from \"./utils/cn\";\n\ntype TabTriggerContent =\n string | { label: string; disabled?: boolean } | ReactNode;\n\n/**\n * Props for the TabMenu component.\n */\n\nexport type TabMenuProps = {\n /**\n * An array of tabs, which can be either a string or an object with a label and an optional disabled state.\n */\n tabs: TabTriggerContent[];\n\n /**\n * An optional array of React nodes representing the content for each tab.\n */\n contents?: ReactNode[];\n\n /**\n * An optional callback function that is called when a tab is clicked, receiving the index of the clicked tab.\n */\n tabOnClick?: (index: number) => void;\n\n /**\n * An optional class name to apply to each tab.\n */\n tabClassName?: string;\n\n /**\n * An optional class name to apply to the Tabs.Root element.\n */\n rootClassName?: string;\n\n /**\n * An optional class name to apply to the Tabs.Content element.\n */\n contentClassName?: string;\n\n /**\n * Optional configuration options for the TabMenu.\n */\n options?: {\n /**\n * The index of the tab that should be selected by default.\n */\n defaultTabIndex?: number;\n\n /**\n * Whether to show an underline below the selected tab.\n */\n underline?: boolean;\n\n /**\n * Whether to animate the transition between tabs.\n */\n animated?: boolean;\n\n /**\n * Whether the tab width should be flexible.\n */\n flexibleTabWidth?: boolean;\n\n /**\n * Whether the tab height should be flexible.\n */\n flexibleTabHeight?: boolean;\n };\n};\n\nconst DEFAULT_TAILWIND_ANIMATION_DURATION = 150;\n\nconst TabMenu: React.FC<TabMenuProps> = ({\n tabs = [],\n contents = [],\n tabOnClick,\n tabClassName,\n rootClassName,\n contentClassName,\n options,\n}) => {\n const {\n defaultTabIndex = 0,\n underline = true,\n animated: animatedOption = true,\n flexibleTabWidth = false,\n flexibleTabHeight = false,\n } = options ?? {};\n\n const listRef = React.useRef<HTMLDivElement>(null);\n const [animated, setAnimated] = React.useState(false);\n const [highlight, setHighlight] = React.useState({ offset: 0, width: 0 });\n\n useEffect(() => {\n if (animatedOption && highlight.width > 0) {\n setTimeout(() => {\n setAnimated(true);\n }, DEFAULT_TAILWIND_ANIMATION_DURATION);\n }\n }, [animatedOption, highlight.width]);\n\n const updateHighlightDimensions = (element: HTMLButtonElement) => {\n const { left: parentLeft } = listRef.current?.getBoundingClientRect() ?? {};\n const { left, width } = element.getBoundingClientRect() ?? {};\n\n setHighlight({\n offset: (left ?? 0) - (parentLeft ?? 0),\n width: width ?? 0,\n });\n };\n\n useEffect(() => {\n const handleResize = throttle(() => {\n const activeTabElement =\n listRef.current?.querySelector<HTMLButtonElement>(\n `[data-state=\"active\"]`,\n );\n\n if (activeTabElement) {\n updateHighlightDimensions(activeTabElement);\n }\n }, 100);\n\n handleResize();\n\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }, []);\n\n const handleTabClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n index: number,\n ) => {\n tabOnClick?.(index);\n updateHighlightDimensions(event.currentTarget as HTMLButtonElement);\n };\n\n const tabTriggerContent = (tab: TabTriggerContent) => {\n if (!tab) {\n return null;\n }\n\n if (React.isValidElement(tab) || typeof tab === \"string\") {\n return tab;\n }\n\n if (typeof tab === \"object\" && \"label\" in tab) {\n return tab.label;\n }\n\n return null;\n };\n\n return (\n <Tabs.Root\n defaultValue={`tab-${defaultTabIndex}`}\n className={cn({ \"h-full\": flexibleTabHeight }, rootClassName)}\n >\n <Tabs.List\n ref={listRef}\n className={cn(\n \"relative\",\n {\n \"flex border-b border-neutral-300 dark:border-neutral-1000\":\n underline,\n },\n { \"h-full\": flexibleTabHeight },\n )}\n >\n {tabs.map(\n (tab, index) =>\n tab && (\n <Tabs.Trigger\n key={`tab-${index}`}\n className={cn(\n \"lg:px-6 md:px-5 px-4 py-4 ui-text-label1 font-semibold data-[state=active]:text-neutral-1300 text-neutral-1000 dark:data-[state=active]:text-neutral-000 dark:text-neutral-300 focus:outline-none focus-visible:outline-gui-focus transition-colors hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-900 dark:active:text-neutral-400 disabled:text-gui-disabled-light dark:disabled:text-gui-disabled-dark disabled:cursor-not-allowed\",\n { \"flex-1\": flexibleTabWidth },\n { \"h-full\": flexibleTabHeight },\n tabClassName,\n )}\n value={`tab-${index}`}\n onClick={(event) => handleTabClick(event, index)}\n disabled={\n typeof tab === \"object\" && \"disabled\" in tab\n ? tab.disabled\n : false\n }\n >\n {tabTriggerContent(tab)}\n </Tabs.Trigger>\n ),\n )}\n <div\n className={cn(\n \"absolute bottom-0 bg-neutral-1300 dark:bg-neutral-000 h-[0.1875rem] w-6\",\n { \"transition-[transform,width]\": animated },\n )}\n style={{\n transform: `translateX(${highlight.offset}px)`,\n width: `${highlight.width}px`,\n }}\n ></div>\n </Tabs.List>\n {contents.map((content, index) => (\n <Tabs.Content\n key={`tab-${index}`}\n value={`tab-${index}`}\n className={contentClassName}\n >\n {content}\n </Tabs.Content>\n ))}\n </Tabs.Root>\n );\n};\n\nexport default TabMenu;\n"],"names":["React","useEffect","Tabs","throttle","cn","DEFAULT_TAILWIND_ANIMATION_DURATION","TabMenu","tabs","contents","tabOnClick","tabClassName","rootClassName","contentClassName","options","defaultTabIndex","underline","animated","animatedOption","flexibleTabWidth","flexibleTabHeight","listRef","useRef","setAnimated","useState","highlight","setHighlight","offset","width","setTimeout","updateHighlightDimensions","element","left","parentLeft","current","getBoundingClientRect","handleResize","activeTabElement","querySelector","window","addEventListener","removeEventListener","handleTabClick","event","index","currentTarget","tabTriggerContent","tab","isValidElement","label","Root","defaultValue","className","List","ref","map","Trigger","key","value","onClick","disabled","div","style","transform","content","Content"],"mappings":"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"}
@@ -4,19 +4,19 @@
4
4
  }
5
5
 
6
6
  .ui-button-lg-base {
7
- @apply ui-button-base ui-text-label1 font-bold h-14 px-7 py-[1.0625rem] gap-3 [&>svg]:!w-6 [&>svg]:!h-6;
7
+ @apply ui-button-base ui-text-label1 font-semibold h-14 px-7 py-[1.0625rem] gap-3 [&>svg]:!w-6 [&>svg]:!h-6;
8
8
  }
9
9
 
10
10
  .ui-button-md-base {
11
- @apply ui-button-base ui-text-label2 font-bold h-12 px-6 py-[0.8125rem] gap-2.5 [&>svg]:!w-6 [&>svg]:!h-6;
11
+ @apply ui-button-base ui-text-label2 font-semibold h-12 px-6 py-[0.8125rem] gap-2.5 [&>svg]:!w-6 [&>svg]:!h-6;
12
12
  }
13
13
 
14
14
  .ui-button-sm-base {
15
- @apply ui-button-base ui-text-label3 font-bold h-10 px-5 py-2.5 gap-2 [&>svg]:!w-5 [&>svg]:!h-5;
15
+ @apply ui-button-base ui-text-label3 font-semibold h-10 px-5 py-2.5 gap-2 [&>svg]:!w-5 [&>svg]:!h-5;
16
16
  }
17
17
 
18
18
  .ui-button-xs-base {
19
- @apply ui-button-base ui-text-label4 font-bold h-9 px-3 py-[0.5625rem] gap-1.5 [&>svg]:!w-4 [&>svg]:!h-4;
19
+ @apply ui-button-base ui-text-label4 font-semibold h-9 px-3 py-[0.5625rem] gap-1.5 [&>svg]:!w-4 [&>svg]:!h-4;
20
20
  }
21
21
 
22
22
  .ui-button-disabled-base {
@@ -1,6 +1,6 @@
1
1
  @layer components {
2
2
  .ui-btn {
3
- @apply text-white bg-cool-black text-label2 font-sans font-bold inline-block rounded p-btn;
3
+ @apply text-white bg-cool-black text-label2 font-sans font-semibold inline-block rounded p-btn;
4
4
  @apply hover:text-white hover:bg-neutral-1100;
5
5
  @apply active:text-white active:bg-neutral-1200;
6
6
  @apply focus:text-white focus:bg-cool-black focus-base;
@@ -24,7 +24,7 @@
24
24
  background-size: 200% 100%;
25
25
  background-position: 0% 0%;
26
26
 
27
- @apply text-white text-label2 font-sans font-bold inline-block rounded p-btn;
27
+ @apply text-white text-label2 font-sans font-semibold inline-block rounded p-btn;
28
28
  @apply focus-base;
29
29
  @apply inline-flex items-center justify-center;
30
30
  }
@@ -40,7 +40,7 @@
40
40
  }
41
41
 
42
42
  .ui-btn-invert {
43
- @apply text-cool-black bg-white text-label2 font-sans font-bold inline-block rounded p-btn;
43
+ @apply text-cool-black bg-white text-label2 font-sans font-semibold inline-block rounded p-btn;
44
44
  @apply hover:text-white hover:bg-active-orange;
45
45
  @apply active:text-white active:bg-red-orange;
46
46
  @apply focus:text-white focus:bg-cool-black focus-base;
@@ -50,7 +50,7 @@
50
50
  }
51
51
 
52
52
  .ui-btn-secondary {
53
- @apply text-cool-black bg-white text-label2 font-sans font-bold inline-block border-btn border-cool-black rounded p-btn;
53
+ @apply text-cool-black bg-white text-label2 font-sans font-semibold inline-block border-btn border-cool-black rounded p-btn;
54
54
  @apply hover:text-cool-black hover:border-active-orange hover:bg-white;
55
55
  @apply active:border-red-orange active:bg-white;
56
56
  @apply focus:border-cool-black focus:bg-white focus-base;
@@ -60,7 +60,7 @@
60
60
  }
61
61
 
62
62
  .ui-btn-secondary-invert {
63
- @apply text-white bg-cool-black text-label2 font-sans font-bold inline-block border-btn border-mid-grey rounded p-btn;
63
+ @apply text-white bg-cool-black text-label2 font-sans font-semibold inline-block border-btn border-mid-grey rounded p-btn;
64
64
  @apply hover:text-white hover:border-active-orange;
65
65
  @apply active:border-red-orange;
66
66
  @apply focus-base;
package/index.d.ts CHANGED
@@ -369,6 +369,11 @@ type PlainCodeViewProps = {
369
369
  language: string;
370
370
  icon: IconName | null;
371
371
  className?: string;
372
+ /**
373
+ * Fired with the copied text once the copy control is used and the text has
374
+ * actually reached the clipboard.
375
+ */
376
+ onCopy?: (text: string) => void;
372
377
  };
373
378
  const PlainCodeView: React.FC<PlainCodeViewProps>;
374
379
  export default PlainCodeView;
@@ -397,6 +402,18 @@ export default TooltipButton;
397
402
  //# sourceMappingURL=TooltipButton.d.ts.map
398
403
  }
399
404
 
405
+ declare module '@ably/ui/core/CodeSnippet/copyToClipboard' {
406
+ /**
407
+ * Writes `text` to the clipboard and only then reports it to `onCopy`. A failed
408
+ * write (denied permission, or a non-secure context where `navigator.clipboard`
409
+ * is absent) leaves nothing on the clipboard, so callers — which use `onCopy` to
410
+ * record that the user took the snippet — must not be told a copy happened.
411
+ */
412
+ const copyToClipboard: (text: string, onCopy?: (text: string) => void) => Promise<void>;
413
+ export default copyToClipboard;
414
+ //# sourceMappingURL=copyToClipboard.d.ts.map
415
+ }
416
+
400
417
  declare module '@ably/ui/core/CodeSnippet/languages' {
401
418
  import { IconName } from ".@ably/ui/core/Icon/types";
402
419
  export interface LanguageInfo {
@@ -476,6 +493,18 @@ export type CodeSnippetProps = {
476
493
  * Whether to wrap code content instead of scrolling
477
494
  */
478
495
  wrapCode?: boolean;
496
+ /**
497
+ * Fired when the user takes the snippet with a copy control, receiving the
498
+ * exact text written to the clipboard. Selecting part of the code and
499
+ * pressing cmd-C does not fire it — a partial selection isn't the user
500
+ * taking the snippet, and callers use this to record that they did. A copy
501
+ * that fails to reach the clipboard does not fire it either.
502
+ *
503
+ * The text may contain a live, unmasked API key — `apiKeys` placeholders are
504
+ * substituted for real before the copy. Do not log it or transmit it to
505
+ * third-party services.
506
+ */
507
+ onCopy?: (text: string) => void;
479
508
  };
480
509
  /**
481
510
  * CodeSnippet component that displays code with language switching capability
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ably/ui",
3
- "version": "18.3.2",
3
+ "version": "18.4.1",
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",
@@ -21,28 +21,28 @@
21
21
  "workerDirectory": "./public"
22
22
  },
23
23
  "devDependencies": {
24
- "@storybook/addon-docs": "^10.4.0",
25
- "@storybook/addon-themes": "^10.4.0",
26
- "@storybook/addon-vitest": "^10.4.0",
27
- "@storybook/react-vite": "^10.4.0",
24
+ "@storybook/addon-docs": "^10.5.0",
25
+ "@storybook/addon-themes": "^10.5.0",
26
+ "@storybook/addon-vitest": "^10.5.0",
27
+ "@storybook/react-vite": "^10.5.0",
28
28
  "@svgr/core": "^8.1.0",
29
29
  "@svgr/plugin-jsx": "^8.1.0",
30
30
  "@svgr/plugin-svgo": "^8.1.0",
31
- "@swc/cli": "^0.8.0",
31
+ "@swc/cli": "^0.8.1",
32
32
  "@swc/core": "^1.13.5",
33
33
  "@tailwindcss/container-queries": "^0.1.1",
34
34
  "@testing-library/react": "^16.3.0",
35
35
  "@types/js-cookie": "^3.0.6",
36
- "@types/node": "^25",
36
+ "@types/node": "^24",
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.61.0",
41
- "@typescript-eslint/parser": "^8.61.0",
40
+ "@typescript-eslint/eslint-plugin": "^8.64.0",
41
+ "@typescript-eslint/parser": "^8.64.0",
42
42
  "@vitejs/plugin-react-swc": "^4.3.0",
43
- "@vitest/browser": "^4.1.8",
44
- "@vitest/browser-playwright": "^4.1.8",
45
- "@vitest/coverage-v8": "^4.1.8",
43
+ "@vitest/browser": "^4.1.10",
44
+ "@vitest/browser-playwright": "^4.1.10",
45
+ "@vitest/coverage-v8": "^4.1.10",
46
46
  "autoprefixer": "^10.5.0",
47
47
  "eslint": "^8.57.1",
48
48
  "eslint-config-prettier": "^10.1.8",
@@ -50,40 +50,41 @@
50
50
  "eslint-plugin-react": "^7.35.0",
51
51
  "eslint-plugin-react-hooks": "^7.1.1",
52
52
  "eslint-plugin-react-perf": "^3.3.3",
53
- "eslint-plugin-storybook": "^10.4.0",
53
+ "eslint-plugin-storybook": "^10.5.0",
54
54
  "heroicons": "^2.2.0",
55
55
  "http-server": "14.1.1",
56
56
  "jsdom": "^29.1.0",
57
- "mixpanel-browser": "^2.79.0",
58
- "msw": "2.14.3",
57
+ "mixpanel-browser": "^2.81.0",
58
+ "msw": "2.15.0",
59
59
  "msw-storybook-addon": "^2.0.7",
60
- "playwright": "^1.60.0",
61
- "posthog-js": "1.386.6",
62
- "prettier": "^3.8.0",
63
- "storybook": "^10.4.0",
60
+ "playwright": "^1.61.1",
61
+ "posthog-js": "1.403.0",
62
+ "prettier": "^3.9.4",
63
+ "storybook": "^10.5.0",
64
64
  "svg-sprite": "^2.0.4",
65
65
  "tailwindcss": "^3.3.6",
66
66
  "ts-node": "^10.9.2",
67
67
  "typescript": "6.0.2",
68
- "vite": "^7.3.2",
69
- "vitest": "^4.1.8"
68
+ "update-browserslist-db": "^1.2.3",
69
+ "vite": "^8.1.2",
70
+ "vitest": "^4.1.10"
70
71
  },
71
72
  "dependencies": {
72
73
  "@heroicons/react": "^2.2.0",
73
74
  "@radix-ui/react-accordion": "^1.2.1",
74
75
  "@radix-ui/react-collapsible": "^1.1.12",
75
76
  "@radix-ui/react-navigation-menu": "^1.2.4",
76
- "@radix-ui/react-select": "^2.2.2",
77
- "@radix-ui/react-switch": "^1.1.1",
77
+ "@radix-ui/react-select": "^2.3.1",
78
+ "@radix-ui/react-switch": "^1.3.1",
78
79
  "@radix-ui/react-tabs": "^1.1.1",
79
80
  "@radix-ui/react-tooltip": "^1.2.8",
80
81
  "array-flat-polyfill": "^1.0.1",
81
82
  "clsx": "^2.1.1",
82
- "dompurify": "^3.4.11",
83
+ "dompurify": "^3.4.12",
83
84
  "embla-carousel": "^8.6.0",
84
85
  "embla-carousel-autoplay": "^8.6.0",
85
86
  "embla-carousel-react": "^8.6.0",
86
- "es-toolkit": "^1.46.0",
87
+ "es-toolkit": "^1.49.0",
87
88
  "highlight.js": "^11.11.1",
88
89
  "highlightjs-curl": "^1.3.0",
89
90
  "js-cookie": "^3.0.7",