@ably/ui 15.5.0-dev.4b8dd74 → 15.5.1-dev.4c700e3d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/Header.js +1 -1
- package/core/Header.js.map +1 -1
- package/core/Meganav.js.map +1 -1
- package/core/Notice.js +1 -1
- package/core/Notice.js.map +1 -1
- package/core/insights/index.js +1 -1
- package/core/insights/index.js.map +1 -1
- package/core/insights/mixpanel.js +1 -1
- package/core/insights/mixpanel.js.map +1 -1
- package/core/insights/posthog.js +1 -1
- package/core/insights/posthog.js.map +1 -1
- package/core/insights/types.js +2 -0
- package/core/insights/types.js.map +1 -0
- package/core/remote-blogs-posts.js +1 -1
- package/core/remote-blogs-posts.js.map +1 -1
- package/core/remote-session-data.js +1 -1
- package/core/remote-session-data.js.map +1 -1
- package/index.d.ts +24 -18
- package/package.json +18 -19
package/core/Header.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useState,useEffect,useRef,useMemo}from"react";import Icon from"./Icon";import cn from"./utils/cn";import Logo from"./Logo";import{componentMaxHeight,HEADER_BOTTOM_MARGIN,HEADER_HEIGHT}from"./utils/heights";import{HeaderLinks}from"./Header/HeaderLinks";import throttle from"lodash.throttle";const FLEXIBLE_DESKTOP_CLASSES="hidden md:flex flex-1 items-center h-full";const Header=({searchBar,searchButton,logoHref,headerLinks,nav,mobileNav,sessionState,themedScrollpoints=[],searchButtonVisibility="all"})=>{const[showMenu,setShowMenu]=useState(false);const[fadingOut,setFadingOut]=useState(false);const[scrollpointClasses,setScrollpointClasses]=useState("");const menuRef=useRef(null);const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};useEffect(()=>{const handleResize=()=>{if(window.innerWidth>=1040){setShowMenu(false)}};window.addEventListener("resize",handleResize);return()=>window.removeEventListener("resize",handleResize)},[]);useEffect(()=>{if(showMenu){document.body.classList.add("overflow-hidden")}else{document.body.classList.remove("overflow-hidden")}return()=>{document.body.classList.remove("overflow-hidden")}},[showMenu]);useEffect(()=>{const handleScroll=()=>{for(const scrollpoint of themedScrollpoints){const element=document.getElementById(scrollpoint.id);if(element){const rect=element.getBoundingClientRect();if(rect.top<=HEADER_HEIGHT&&rect.bottom>=HEADER_HEIGHT){setScrollpointClasses(scrollpoint.className);return}}}};const throttledHandleScroll=throttle(handleScroll,150);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints]);const wrappedSearchButton=useMemo(()=>searchButton?React.createElement("div",{className:"text-neutral-1300 dark:text-neutral-000 flex items-center p-6"},searchButton):null,[searchButton]);return React.createElement(React.Fragment,null,React.createElement("header",{role:"banner",className:cn("fixed top-0 left-0 w-full z-10 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 transition-colors px-24 md:px-64",scrollpointClasses),style:{height:HEADER_HEIGHT}},React.createElement("div",{className:"flex items-center h-full"},React.createElement("nav",{className:"flex flex-1 h-full items-center"},["light","dark"].map(theme=>React.createElement(Logo,{key:theme,href:logoHref,theme:theme,additionalLinkAttrs:{className:cn("h-full focus-base rounded mr-32 w-[108px]",{"flex dark:hidden":theme==="light","hidden dark:flex":theme==="dark"})}})),React.createElement("div",{className:FLEXIBLE_DESKTOP_CLASSES},nav)),React.createElement("div",{className:"flex md:hidden flex-1 items-center justify-end gap-24 h-full"},searchButtonVisibility!=="desktop"?wrappedSearchButton:null,React.createElement("button",{className:"cursor-pointer focus-base rounded flex items-center",onClick:()=>setShowMenu(!showMenu),"aria-expanded":showMenu,"aria-controls":"mobile-menu","aria-label":"Toggle menu"},React.createElement(Icon,{name:showMenu?"icon-gui-x-mark-outline":"icon-gui-bars-3-outline",additionalCSS:"text-neutral-1300 dark:text-neutral-000",size:"1.5rem"}))),searchBar?React.createElement("div",{className:cn(FLEXIBLE_DESKTOP_CLASSES,"justify-center")},searchBar):null,React.createElement(HeaderLinks,{className:FLEXIBLE_DESKTOP_CLASSES,headerLinks:headerLinks,sessionState:sessionState,searchButton:wrappedSearchButton,searchButtonVisibility:searchButtonVisibility}))),showMenu?React.createElement(React.Fragment,null,React.createElement("div",{className:cn("fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300",{"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]":!fadingOut,"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]":fadingOut}),onClick:closeMenu,onKeyDown:e=>e.key==="Escape"&&closeMenu(),role:"presentation"}),React.createElement("div",{id:"mobile-menu",className:"md:hidden fixed flex flex-col top-[76px] overflow-y-hidden
|
|
1
|
+
import React,{useState,useEffect,useRef,useMemo}from"react";import Icon from"./Icon";import cn from"./utils/cn";import Logo from"./Logo";import{componentMaxHeight,HEADER_BOTTOM_MARGIN,HEADER_HEIGHT}from"./utils/heights";import{HeaderLinks}from"./Header/HeaderLinks";import throttle from"lodash.throttle";const FLEXIBLE_DESKTOP_CLASSES="hidden md:flex flex-1 items-center h-full";const MAX_MOBILE_MENU_WIDTH="560px";const Header=({searchBar,searchButton,logoHref,headerLinks,nav,mobileNav,sessionState,themedScrollpoints=[],searchButtonVisibility="all"})=>{const[showMenu,setShowMenu]=useState(false);const[fadingOut,setFadingOut]=useState(false);const[scrollpointClasses,setScrollpointClasses]=useState("");const menuRef=useRef(null);const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};useEffect(()=>{const handleResize=()=>{if(window.innerWidth>=1040){setShowMenu(false)}};window.addEventListener("resize",handleResize);return()=>window.removeEventListener("resize",handleResize)},[]);useEffect(()=>{if(showMenu){document.body.classList.add("overflow-hidden")}else{document.body.classList.remove("overflow-hidden")}return()=>{document.body.classList.remove("overflow-hidden")}},[showMenu]);useEffect(()=>{const handleScroll=()=>{for(const scrollpoint of themedScrollpoints){const element=document.getElementById(scrollpoint.id);if(element){const rect=element.getBoundingClientRect();if(rect.top<=HEADER_HEIGHT&&rect.bottom>=HEADER_HEIGHT){setScrollpointClasses(scrollpoint.className);return}}}};const throttledHandleScroll=throttle(handleScroll,150);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints]);const wrappedSearchButton=useMemo(()=>searchButton?React.createElement("div",{className:"text-neutral-1300 dark:text-neutral-000 flex items-center p-6"},searchButton):null,[searchButton]);return React.createElement(React.Fragment,null,React.createElement("header",{role:"banner",className:cn("fixed top-0 left-0 w-full z-10 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 transition-colors px-24 md:px-64",scrollpointClasses),style:{height:HEADER_HEIGHT}},React.createElement("div",{className:"flex items-center h-full"},React.createElement("nav",{className:"flex flex-1 h-full items-center"},["light","dark"].map(theme=>React.createElement(Logo,{key:theme,href:logoHref,theme:theme,additionalLinkAttrs:{className:cn("h-full focus-base rounded mr-32 w-[108px]",{"flex dark:hidden":theme==="light","hidden dark:flex":theme==="dark"})}})),React.createElement("div",{className:FLEXIBLE_DESKTOP_CLASSES},nav)),React.createElement("div",{className:"flex md:hidden flex-1 items-center justify-end gap-24 h-full"},searchButtonVisibility!=="desktop"?wrappedSearchButton:null,React.createElement("button",{className:"cursor-pointer focus-base rounded flex items-center",onClick:()=>setShowMenu(!showMenu),"aria-expanded":showMenu,"aria-controls":"mobile-menu","aria-label":"Toggle menu"},React.createElement(Icon,{name:showMenu?"icon-gui-x-mark-outline":"icon-gui-bars-3-outline",additionalCSS:"text-neutral-1300 dark:text-neutral-000",size:"1.5rem"}))),searchBar?React.createElement("div",{className:cn(FLEXIBLE_DESKTOP_CLASSES,"justify-center")},searchBar):null,React.createElement(HeaderLinks,{className:FLEXIBLE_DESKTOP_CLASSES,headerLinks:headerLinks,sessionState:sessionState,searchButton:wrappedSearchButton,searchButtonVisibility:searchButtonVisibility}))),showMenu?React.createElement(React.Fragment,null,React.createElement("div",{className:cn("fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300",{"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]":!fadingOut,"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]":fadingOut}),onClick:closeMenu,onKeyDown:e=>e.key==="Escape"&&closeMenu(),role:"presentation"}),React.createElement("div",{id:"mobile-menu",className:"md:hidden fixed flex flex-col top-[76px] overflow-y-hidden mx-12 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-20",style:{maxWidth:MAX_MOBILE_MENU_WIDTH,maxHeight:componentMaxHeight(HEADER_HEIGHT,HEADER_BOTTOM_MARGIN)},ref:menuRef,role:"navigation"},mobileNav,React.createElement(HeaderLinks,{headerLinks:headerLinks,sessionState:sessionState}))):null)};export default Header;
|
|
2
2
|
//# sourceMappingURL=Header.js.map
|
package/core/Header.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Header.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, ReactNode, useMemo } from \"react\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn\";\nimport Logo from \"./Logo\";\nimport {\n componentMaxHeight,\n HEADER_BOTTOM_MARGIN,\n HEADER_HEIGHT,\n} from \"./utils/heights\";\nimport { HeaderLinks } from \"./Header/HeaderLinks\";\nimport throttle from \"lodash.throttle\";\nimport { Theme } from \"./styles/colors/types\";\n\nexport type ThemedScrollpoint = {\n id: string;\n className: string;\n};\n\n/**\n * Props for the Header component.\n */\nexport type HeaderProps = {\n /**\n * Optional search bar element.\n */\n searchBar?: ReactNode;\n\n /**\n * Optional search button element.\n */\n searchButton?: ReactNode;\n\n /**\n * URL for the logo link.\n */\n logoHref?: string;\n\n /**\n * Array of header links.\n */\n headerLinks?: {\n /**\n * URL for the link.\n */\n href: string;\n\n /**\n * Label for the link.\n */\n label: string;\n\n /**\n * Indicates if the link should open in a new tab.\n */\n external?: boolean;\n }[];\n\n /**\n * Optional desktop navigation element.\n */\n nav?: ReactNode;\n\n /**\n * Optional mobile navigation element.\n */\n mobileNav?: ReactNode;\n\n /**\n * State of the user session.\n */\n sessionState?: {\n /**\n * Indicates if the user is signed in.\n */\n signedIn: boolean;\n\n /**\n * Account information.\n */\n account: {\n /**\n * Links related to the account.\n */\n links: {\n /**\n * Dashboard link information.\n */\n dashboard: {\n /**\n * URL for the dashboard link.\n */\n href: string;\n };\n };\n };\n };\n\n /**\n * Array of themed scrollpoints. The header will change its appearance based on the scrollpoint in view.\n */\n themedScrollpoints?: ThemedScrollpoint[];\n\n /**\n * Visibility setting for the search button.\n * - \"all\": Visible on all devices.\n * - \"desktop\": Visible only on desktop devices.\n * - \"mobile\": Visible only on mobile devices.\n */\n searchButtonVisibility?: \"all\" | \"desktop\" | \"mobile\";\n};\n\nconst FLEXIBLE_DESKTOP_CLASSES = \"hidden md:flex flex-1 items-center h-full\";\n\nconst Header: React.FC<HeaderProps> = ({\n searchBar,\n searchButton,\n logoHref,\n headerLinks,\n nav,\n mobileNav,\n sessionState,\n themedScrollpoints = [],\n searchButtonVisibility = \"all\",\n}) => {\n const [showMenu, setShowMenu] = useState(false);\n const [fadingOut, setFadingOut] = useState(false);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\"\");\n const menuRef = useRef<HTMLDivElement>(null);\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth >= 1040) {\n setShowMenu(false);\n }\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n if (showMenu) {\n document.body.classList.add(\"overflow-hidden\");\n } else {\n document.body.classList.remove(\"overflow-hidden\");\n }\n\n // Cleanup on unmount\n return () => {\n document.body.classList.remove(\"overflow-hidden\");\n };\n }, [showMenu]);\n\n useEffect(() => {\n const handleScroll = () => {\n for (const scrollpoint of themedScrollpoints) {\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT) {\n setScrollpointClasses(scrollpoint.className);\n return;\n }\n }\n }\n };\n\n const throttledHandleScroll = throttle(handleScroll, 150);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints]);\n\n const wrappedSearchButton = useMemo(\n () =>\n searchButton ? (\n <div className=\"text-neutral-1300 dark:text-neutral-000 flex items-center p-6\">\n {searchButton}\n </div>\n ) : null,\n [searchButton],\n );\n\n return (\n <>\n <header\n role=\"banner\"\n className={cn(\n \"fixed top-0 left-0 w-full z-10 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 transition-colors px-24 md:px-64\",\n scrollpointClasses,\n )}\n style={{ height: HEADER_HEIGHT }}\n >\n <div className=\"flex items-center h-full\">\n <nav className=\"flex flex-1 h-full items-center\">\n {([\"light\", \"dark\"] as Theme[]).map((theme) => (\n <Logo\n key={theme}\n href={logoHref}\n theme={theme}\n additionalLinkAttrs={{\n className: cn(\"h-full focus-base rounded mr-32 w-[108px]\", {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n }),\n }}\n />\n ))}\n <div className={FLEXIBLE_DESKTOP_CLASSES}>{nav}</div>\n </nav>\n <div className=\"flex md:hidden flex-1 items-center justify-end gap-24 h-full\">\n {searchButtonVisibility !== \"desktop\" ? wrappedSearchButton : null}\n <button\n className=\"cursor-pointer focus-base rounded flex items-center\"\n onClick={() => setShowMenu(!showMenu)}\n aria-expanded={showMenu}\n aria-controls=\"mobile-menu\"\n aria-label=\"Toggle menu\"\n >\n <Icon\n name={\n showMenu\n ? \"icon-gui-x-mark-outline\"\n : \"icon-gui-bars-3-outline\"\n }\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n size=\"1.5rem\"\n />\n </button>\n </div>\n {searchBar ? (\n <div className={cn(FLEXIBLE_DESKTOP_CLASSES, \"justify-center\")}>\n {searchBar}\n </div>\n ) : null}\n <HeaderLinks\n className={FLEXIBLE_DESKTOP_CLASSES}\n headerLinks={headerLinks}\n sessionState={sessionState}\n searchButton={wrappedSearchButton}\n searchButtonVisibility={searchButtonVisibility}\n />\n </div>\n </header>\n {showMenu ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300\",\n {\n \"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]\":\n !fadingOut,\n \"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]\":\n fadingOut,\n },\n )}\n onClick={closeMenu}\n onKeyDown={(e) => e.key === \"Escape\" && closeMenu()}\n role=\"presentation\"\n />\n <div\n id=\"mobile-menu\"\n className=\"md:hidden fixed flex flex-col top-[76px] overflow-y-hidden left-0 right-0 mx-12 bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-20\"\n style={{\n maxHeight: componentMaxHeight(\n HEADER_HEIGHT,\n HEADER_BOTTOM_MARGIN,\n ),\n }}\n ref={menuRef}\n role=\"navigation\"\n >\n {mobileNav}\n <HeaderLinks\n headerLinks={headerLinks}\n sessionState={sessionState}\n />\n </div>\n </>\n ) : null}\n </>\n );\n};\n\nexport default Header;\n"],"names":["React","useState","useEffect","useRef","useMemo","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","FLEXIBLE_DESKTOP_CLASSES","Header","searchBar","searchButton","logoHref","headerLinks","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","showMenu","setShowMenu","fadingOut","setFadingOut","scrollpointClasses","setScrollpointClasses","menuRef","closeMenu","setTimeout","handleResize","window","innerWidth","addEventListener","removeEventListener","document","body","classList","add","remove","handleScroll","scrollpoint","element","getElementById","id","rect","getBoundingClientRect","top","bottom","className","throttledHandleScroll","wrappedSearchButton","div","header","role","style","height","map","theme","key","href","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxHeight","ref"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/Header.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, ReactNode, useMemo } from \"react\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn\";\nimport Logo from \"./Logo\";\nimport {\n componentMaxHeight,\n HEADER_BOTTOM_MARGIN,\n HEADER_HEIGHT,\n} from \"./utils/heights\";\nimport { HeaderLinks } from \"./Header/HeaderLinks\";\nimport throttle from \"lodash.throttle\";\nimport { Theme } from \"./styles/colors/types\";\n\nexport type ThemedScrollpoint = {\n id: string;\n className: string;\n};\n\n/**\n * Props for the Header component.\n */\nexport type HeaderProps = {\n /**\n * Optional search bar element.\n */\n searchBar?: ReactNode;\n\n /**\n * Optional search button element.\n */\n searchButton?: ReactNode;\n\n /**\n * URL for the logo link.\n */\n logoHref?: string;\n\n /**\n * Array of header links.\n */\n headerLinks?: {\n /**\n * URL for the link.\n */\n href: string;\n\n /**\n * Label for the link.\n */\n label: string;\n\n /**\n * Indicates if the link should open in a new tab.\n */\n external?: boolean;\n }[];\n\n /**\n * Optional desktop navigation element.\n */\n nav?: ReactNode;\n\n /**\n * Optional mobile navigation element.\n */\n mobileNav?: ReactNode;\n\n /**\n * State of the user session.\n */\n sessionState?: {\n /**\n * Indicates if the user is signed in.\n */\n signedIn: boolean;\n\n /**\n * Account information.\n */\n account: {\n /**\n * Links related to the account.\n */\n links: {\n /**\n * Dashboard link information.\n */\n dashboard: {\n /**\n * URL for the dashboard link.\n */\n href: string;\n };\n };\n };\n };\n\n /**\n * Array of themed scrollpoints. The header will change its appearance based on the scrollpoint in view.\n */\n themedScrollpoints?: ThemedScrollpoint[];\n\n /**\n * Visibility setting for the search button.\n * - \"all\": Visible on all devices.\n * - \"desktop\": Visible only on desktop devices.\n * - \"mobile\": Visible only on mobile devices.\n */\n searchButtonVisibility?: \"all\" | \"desktop\" | \"mobile\";\n};\n\nconst FLEXIBLE_DESKTOP_CLASSES = \"hidden md:flex flex-1 items-center h-full\";\n\n/**\n * Maximum width before the menu expanded into full width\n */\nconst MAX_MOBILE_MENU_WIDTH = \"560px\";\n\nconst Header: React.FC<HeaderProps> = ({\n searchBar,\n searchButton,\n logoHref,\n headerLinks,\n nav,\n mobileNav,\n sessionState,\n themedScrollpoints = [],\n searchButtonVisibility = \"all\",\n}) => {\n const [showMenu, setShowMenu] = useState(false);\n const [fadingOut, setFadingOut] = useState(false);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\"\");\n const menuRef = useRef<HTMLDivElement>(null);\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth >= 1040) {\n setShowMenu(false);\n }\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n if (showMenu) {\n document.body.classList.add(\"overflow-hidden\");\n } else {\n document.body.classList.remove(\"overflow-hidden\");\n }\n\n // Cleanup on unmount\n return () => {\n document.body.classList.remove(\"overflow-hidden\");\n };\n }, [showMenu]);\n\n useEffect(() => {\n const handleScroll = () => {\n for (const scrollpoint of themedScrollpoints) {\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT) {\n setScrollpointClasses(scrollpoint.className);\n return;\n }\n }\n }\n };\n\n const throttledHandleScroll = throttle(handleScroll, 150);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints]);\n\n const wrappedSearchButton = useMemo(\n () =>\n searchButton ? (\n <div className=\"text-neutral-1300 dark:text-neutral-000 flex items-center p-6\">\n {searchButton}\n </div>\n ) : null,\n [searchButton],\n );\n\n return (\n <>\n <header\n role=\"banner\"\n className={cn(\n \"fixed top-0 left-0 w-full z-10 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 transition-colors px-24 md:px-64\",\n scrollpointClasses,\n )}\n style={{ height: HEADER_HEIGHT }}\n >\n <div className=\"flex items-center h-full\">\n <nav className=\"flex flex-1 h-full items-center\">\n {([\"light\", \"dark\"] as Theme[]).map((theme) => (\n <Logo\n key={theme}\n href={logoHref}\n theme={theme}\n additionalLinkAttrs={{\n className: cn(\"h-full focus-base rounded mr-32 w-[108px]\", {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n }),\n }}\n />\n ))}\n <div className={FLEXIBLE_DESKTOP_CLASSES}>{nav}</div>\n </nav>\n <div className=\"flex md:hidden flex-1 items-center justify-end gap-24 h-full\">\n {searchButtonVisibility !== \"desktop\" ? wrappedSearchButton : null}\n <button\n className=\"cursor-pointer focus-base rounded flex items-center\"\n onClick={() => setShowMenu(!showMenu)}\n aria-expanded={showMenu}\n aria-controls=\"mobile-menu\"\n aria-label=\"Toggle menu\"\n >\n <Icon\n name={\n showMenu\n ? \"icon-gui-x-mark-outline\"\n : \"icon-gui-bars-3-outline\"\n }\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n size=\"1.5rem\"\n />\n </button>\n </div>\n {searchBar ? (\n <div className={cn(FLEXIBLE_DESKTOP_CLASSES, \"justify-center\")}>\n {searchBar}\n </div>\n ) : null}\n <HeaderLinks\n className={FLEXIBLE_DESKTOP_CLASSES}\n headerLinks={headerLinks}\n sessionState={sessionState}\n searchButton={wrappedSearchButton}\n searchButtonVisibility={searchButtonVisibility}\n />\n </div>\n </header>\n {showMenu ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300\",\n {\n \"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]\":\n !fadingOut,\n \"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]\":\n fadingOut,\n },\n )}\n onClick={closeMenu}\n onKeyDown={(e) => e.key === \"Escape\" && closeMenu()}\n role=\"presentation\"\n />\n <div\n id=\"mobile-menu\"\n className=\"md:hidden fixed flex flex-col top-[76px] overflow-y-hidden mx-12 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-20\"\n style={{\n maxWidth: MAX_MOBILE_MENU_WIDTH,\n maxHeight: componentMaxHeight(\n HEADER_HEIGHT,\n HEADER_BOTTOM_MARGIN,\n ),\n }}\n ref={menuRef}\n role=\"navigation\"\n >\n {mobileNav}\n <HeaderLinks\n headerLinks={headerLinks}\n sessionState={sessionState}\n />\n </div>\n </>\n ) : null}\n </>\n );\n};\n\nexport default Header;\n"],"names":["React","useState","useEffect","useRef","useMemo","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","searchBar","searchButton","logoHref","headerLinks","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","showMenu","setShowMenu","fadingOut","setFadingOut","scrollpointClasses","setScrollpointClasses","menuRef","closeMenu","setTimeout","handleResize","window","innerWidth","addEventListener","removeEventListener","document","body","classList","add","remove","handleScroll","scrollpoint","element","getElementById","id","rect","getBoundingClientRect","top","bottom","className","throttledHandleScroll","wrappedSearchButton","div","header","role","style","height","map","theme","key","href","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxWidth","maxHeight","ref"],"mappings":"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"}
|
package/core/Meganav.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Meganav.tsx"],"sourcesContent":["import React, { ReactNode, useEffect, useState } from \"react\";\n\nimport { connectState } from \"./remote-data-store.js\";\nimport { selectSessionData } from \"./remote-session-data.js\";\n\nimport Logo from \"./Logo\";\nimport MeganavData from \"./Meganav/component.json\";\nimport MeganavScripts from \"./Meganav/component.js\";\nimport MeganavItemsDesktop from \"./MeganavItemsDesktop\";\nimport MeganavItemsSignedIn from \"./MeganavItemsSignedIn\";\nimport MeganavItemsMobile from \"./MeganavItemsMobile\";\nimport Notice from \"./Notice\";\nimport _absUrl from \"./url-base.js\";\nimport MeganavContentProducts from \"./MeganavContentProducts\";\nimport MeganavContentUseCases from \"./MeganavContentUseCases\";\nimport MeganavContentCompany from \"./MeganavContentCompany\";\nimport MeganavContentDevelopers from \"./MeganavContentDevelopers\";\nimport MeganavSearch from \"./MeganavSearch\";\nimport { ColorClass } from \"./styles/colors/types\";\n\nexport type MeganavTheme = {\n backgroundColor?: ColorClass;\n textColor?: ColorClass;\n buttonBackgroundColor?: ColorClass;\n buttonTextColor?: ColorClass;\n mobileMenuColor: ColorClass;\n logoTextColor?: ColorClass;\n barShadow?: string;\n};\n\nexport type AbsUrl = (path: string) => string;\n\nexport type MeganavPaths = {\n logo?: string;\n iconSprites: string;\n ablyStack: string;\n blogThumb1: string;\n blogThumb2: string;\n blogThumb3: string;\n awsLogo?: string;\n};\n\nexport type MeganavPanels = {\n [index: string]: ({\n paths,\n absUrl,\n statusUrl,\n }: {\n paths?: MeganavPaths;\n absUrl: (path: string) => string;\n statusUrl: string;\n }) => ReactNode;\n};\n\nexport type MeganavSessionState = {\n signedIn: boolean;\n logOut: {\n token: string;\n href: string;\n text: string;\n };\n accountName: string;\n preferredEmail: string;\n account: {\n links: {\n dashboard: {\n href: string;\n };\n };\n };\n mySettings: {\n text: string;\n href: string;\n };\n myAccessTokens: {\n text: string;\n href: string;\n };\n};\n\ntype SignInProps = {\n sessionState: MeganavSessionState;\n theme: MeganavTheme;\n loginLink: string;\n absUrl: AbsUrl;\n searchDataId?: string;\n};\n\
|
|
1
|
+
{"version":3,"sources":["../../src/core/Meganav.tsx"],"sourcesContent":["import React, { ReactNode, useEffect, useState } from \"react\";\n\nimport { connectState } from \"./remote-data-store.js\";\nimport { selectSessionData } from \"./remote-session-data.js\";\n\nimport Logo from \"./Logo\";\nimport MeganavData from \"./Meganav/component.json\";\nimport MeganavScripts from \"./Meganav/component.js\";\nimport MeganavItemsDesktop from \"./MeganavItemsDesktop\";\nimport MeganavItemsSignedIn from \"./MeganavItemsSignedIn\";\nimport MeganavItemsMobile from \"./MeganavItemsMobile\";\nimport Notice from \"./Notice\";\nimport _absUrl from \"./url-base.js\";\nimport MeganavContentProducts from \"./MeganavContentProducts\";\nimport MeganavContentUseCases from \"./MeganavContentUseCases\";\nimport MeganavContentCompany from \"./MeganavContentCompany\";\nimport MeganavContentDevelopers from \"./MeganavContentDevelopers\";\nimport MeganavSearch from \"./MeganavSearch\";\nimport { ColorClass } from \"./styles/colors/types\";\n\nexport type MeganavTheme = {\n backgroundColor?: ColorClass;\n textColor?: ColorClass;\n buttonBackgroundColor?: ColorClass;\n buttonTextColor?: ColorClass;\n mobileMenuColor: ColorClass;\n logoTextColor?: ColorClass;\n barShadow?: string;\n};\n\nexport type AbsUrl = (path: string) => string;\n\nexport type MeganavPaths = {\n logo?: string;\n iconSprites: string;\n ablyStack: string;\n blogThumb1: string;\n blogThumb2: string;\n blogThumb3: string;\n awsLogo?: string;\n};\n\nexport type MeganavPanels = {\n [index: string]: ({\n paths,\n absUrl,\n statusUrl,\n }: {\n paths?: MeganavPaths;\n absUrl: (path: string) => string;\n statusUrl: string;\n }) => ReactNode;\n};\n\nexport type MeganavSessionState = {\n signedIn: boolean;\n logOut: {\n token: string;\n href: string;\n text: string;\n };\n accountName: string;\n preferredEmail: string;\n account: {\n links: {\n dashboard: {\n href: string;\n };\n };\n };\n mySettings: {\n text: string;\n href: string;\n };\n myAccessTokens: {\n text: string;\n href: string;\n };\n};\n\ntype SignInProps = {\n sessionState: MeganavSessionState;\n theme: MeganavTheme;\n loginLink: string;\n absUrl: AbsUrl;\n searchDataId?: string;\n};\n\n// This type is based on the API response from the notice API and the data\n// passed into the Meganav component, which then turns it into something\n// the Notice component can use. The type is exported for the benefit of\n// Voltaire\nexport type MeganavNoticeProps = {\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\ntype MeganavProps = {\n paths?: MeganavPaths;\n themeName: \"white\" | \"black\" | \"transparentToWhite\";\n notice?: MeganavNoticeProps;\n loginLink?: string;\n urlBase?: string;\n addSearchApiKey: string;\n statusUrl: string;\n searchDataId?: string;\n};\n\nconst SignIn = ({\n sessionState,\n theme,\n loginLink,\n absUrl,\n searchDataId,\n}: SignInProps) => {\n return sessionState.signedIn ? (\n <MeganavItemsSignedIn\n absUrl={absUrl}\n sessionState={sessionState}\n theme={theme}\n searchDataId={searchDataId}\n />\n ) : (\n <ul className=\"hidden md:flex items-center\">\n <li className=\"ui-meganav-item\">\n <a\n href={absUrl(\"/contact\")}\n className={`ui-meganav-link ${theme.textColor}`}\n data-id=\"meganav-link\"\n >\n Contact us\n </a>\n </li>\n <li className=\"ui-meganav-item\">\n <a\n href={absUrl(loginLink)}\n className={`ui-meganav-link mr-0 ${theme.textColor}`}\n data-id=\"meganav-link\"\n >\n Login\n </a>\n </li>\n <li className=\"ui-meganav-item\">\n <MeganavSearch absUrl={absUrl} dataId={searchDataId} />\n </li>\n <li className=\"ui-meganav-item\">\n <a\n href={absUrl(\"/sign-up\")}\n data-id=\"meganav-sign-up-btn\"\n className={`ui-btn p-btn-small ${theme.buttonBackgroundColor} ${theme.buttonTextColor}`}\n >\n Sign up free\n </a>\n </li>\n </ul>\n );\n};\n\nconst SignInPlaceholder = () => <div />;\n\nconst panels = {\n MeganavContentProducts,\n MeganavContentUseCases,\n MeganavContentCompany,\n MeganavContentDevelopers,\n};\n\nconst Meganav = ({\n paths,\n themeName = \"white\",\n notice,\n loginLink = \"/login\",\n urlBase,\n addSearchApiKey,\n statusUrl,\n searchDataId,\n}: MeganavProps) => {\n const [sessionState, setSessionState] = useState<MeganavSessionState>();\n\n useEffect(() => {\n // Note if state is never updated, sessionState stays null and never removes the placeholder.\n // This makes SSR consistent (ie. we always show the placeholder)\n connectState(selectSessionData, setSessionState);\n }, []);\n\n useEffect(() => {\n const teardown = MeganavScripts({ themeName, addSearchApiKey });\n return () => teardown();\n }, [sessionState]);\n\n const theme = MeganavData.themes[themeName] as MeganavTheme;\n const absUrl = (path: string) => _absUrl(path, urlBase);\n\n return (\n <nav\n className={`ui-meganav-wrapper ${theme.backgroundColor} ${theme.barShadow}`}\n data-id=\"meganav\"\n aria-label=\"Main\"\n >\n {notice && <Notice {...notice.props} config={notice.config} />}\n <div className=\"ui-meganav ui-grid-px\">\n <div className=\"mr-24\">\n <Logo dataId=\"meganav-logo\" href={urlBase} logoUrl={paths?.logo} />\n </div>\n\n <MeganavItemsDesktop\n panels={panels}\n paths={paths}\n theme={theme}\n absUrl={absUrl}\n statusUrl={statusUrl}\n />\n\n {/* Because we load the session state through fetch, we display a placeholder until fetch returns */}\n {sessionState ? (\n <SignIn\n sessionState={sessionState}\n theme={theme}\n loginLink={loginLink}\n absUrl={absUrl}\n searchDataId={searchDataId}\n />\n ) : (\n <SignInPlaceholder />\n )}\n\n <MeganavItemsMobile\n panels={panels}\n sessionState={sessionState}\n paths={paths}\n theme={theme}\n loginLink={loginLink}\n absUrl={absUrl}\n statusUrl={statusUrl}\n searchDataId={searchDataId}\n />\n </div>\n </nav>\n );\n};\n\nexport default Meganav;\n"],"names":["React","useEffect","useState","connectState","selectSessionData","Logo","MeganavData","MeganavScripts","MeganavItemsDesktop","MeganavItemsSignedIn","MeganavItemsMobile","Notice","_absUrl","MeganavContentProducts","MeganavContentUseCases","MeganavContentCompany","MeganavContentDevelopers","MeganavSearch","SignIn","sessionState","theme","loginLink","absUrl","searchDataId","signedIn","ul","className","li","a","href","textColor","data-id","dataId","buttonBackgroundColor","buttonTextColor","SignInPlaceholder","div","panels","Meganav","paths","themeName","notice","urlBase","addSearchApiKey","statusUrl","setSessionState","teardown","themes","path","nav","backgroundColor","barShadow","aria-label","props","config","logoUrl","logo"],"mappings":"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"}
|
package/core/Notice.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import React,{useEffect}from"react";import
|
|
1
|
+
import React,{useEffect}from"react";import Icon from"./Icon";import cn from"./utils/cn.js";import NoticeScripts from"./Notice/component.js";const defaultTextColor="text-neutral-000";const contentWrapperClasses="w-full pr-8 ui-text-p3 self-center";const ContentWrapper=({buttonLink,textColor=defaultTextColor,children})=>buttonLink?React.createElement("a",{href:buttonLink,className:cn(contentWrapperClasses,textColor)},children):React.createElement("div",{className:cn(contentWrapperClasses,textColor)},children);const Notice=({buttonLink,buttonLabel,bodyText,title,config,closeBtn,bgColor="bg-gradient-active-orange",textColor=defaultTextColor})=>{useEffect(()=>{NoticeScripts({bannerContainer:document.querySelector('[data-id="ui-notice"]'),cookieId:config?.cookieId,noticeId:config?.noticeId,options:{collapse:config?.options?.collapse||false}})},[]);return React.createElement("div",{className:cn("ui-announcement",bgColor,textColor),"data-id":"ui-notice",style:{maxHeight:0,overflow:"hidden"}},React.createElement("div",{className:"ui-grid-px py-16 max-w-screen-xl mx-auto flex items-start"},React.createElement(ContentWrapper,{buttonLink:buttonLink??"#"},React.createElement("strong",{className:"font-bold whitespace-nowrap pr-4"},title),React.createElement("span",{className:"pr-4"},bodyText),buttonLabel&&React.createElement("span",{className:"underline cursor-pointer whitespace-nowrap"},buttonLabel)),closeBtn&&React.createElement("button",{type:"button",className:"ml-auto h-20 w-20 border-none bg-none self-baseline"},React.createElement(Icon,{name:"icon-gui-x-mark-outline",size:"1.25rem",color:textColor}))))};export default Notice;
|
|
2
2
|
//# sourceMappingURL=Notice.js.map
|
package/core/Notice.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/Notice.tsx"],"sourcesContent":["import React, { ReactNode, useEffect } from \"react\";\n\nimport
|
|
1
|
+
{"version":3,"sources":["../../src/core/Notice.tsx"],"sourcesContent":["import React, { ReactNode, useEffect } from \"react\";\n\nimport { ColorClass, ColorThemeSet } from \"./styles/colors/types\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn.js\";\nimport NoticeScripts from \"./Notice/component.js\";\n\ntype ContentWrapperProps = {\n buttonLink: string;\n children: ReactNode;\n textColor?: ColorClass | ColorThemeSet;\n};\n\n// TODO(jamiehenson):\n// This type is a bit messed up currently due to the NoticeScripts import being interpreted as NoticeProps.\n// Plan is to TS-ify the JS assets too, so this can be rectified then. The NoticeScripts-oriented props are\n// the ones after the line break.\nexport type NoticeProps = {\n buttonLink?: string;\n buttonLabel?: string;\n bodyText?: string;\n title?: string;\n closeBtn?: boolean;\n config?: {\n options: {\n collapse: boolean;\n };\n noticeId: string | number;\n cookieId: string;\n };\n bgColor?: string;\n textColor?: ColorClass | ColorThemeSet;\n\n bannerContainer?: Element | null;\n cookieId?: string;\n noticeId?: string;\n options?: { collapse: boolean };\n};\n\nconst defaultTextColor = \"text-neutral-000\";\n\nconst contentWrapperClasses = \"w-full pr-8 ui-text-p3 self-center\";\n\nconst ContentWrapper = ({ buttonLink, textColor = defaultTextColor, children }: ContentWrapperProps) =>\n buttonLink ? (\n <a href={buttonLink} className={cn(contentWrapperClasses, textColor)}>\n {children}\n </a>\n ) : (\n <div className={cn(contentWrapperClasses, textColor)}>{children}</div>\n );\n\nconst Notice = ({\n buttonLink,\n buttonLabel,\n bodyText,\n title,\n config,\n closeBtn,\n bgColor = \"bg-gradient-active-orange\",\n textColor = defaultTextColor,\n}: NoticeProps) => {\n useEffect(() => {\n NoticeScripts({\n bannerContainer: document.querySelector('[data-id=\"ui-notice\"]'),\n cookieId: config?.cookieId,\n noticeId: config?.noticeId,\n options: {\n collapse: config?.options?.collapse || false,\n },\n });\n }, []);\n\n return (\n <div\n className={cn(\"ui-announcement\", bgColor, textColor)}\n data-id=\"ui-notice\"\n style={{ maxHeight: 0, overflow: \"hidden\" }}\n >\n <div className=\"ui-grid-px py-16 max-w-screen-xl mx-auto flex items-start\">\n <ContentWrapper buttonLink={buttonLink ?? \"#\"}>\n <strong className=\"font-bold whitespace-nowrap pr-4\">{title}</strong>\n <span className=\"pr-4\">{bodyText}</span>\n {buttonLabel && (\n <span className=\"underline cursor-pointer whitespace-nowrap\">\n {buttonLabel}\n </span>\n )}\n </ContentWrapper>\n\n {closeBtn && (\n <button\n type=\"button\"\n className=\"ml-auto h-20 w-20 border-none bg-none self-baseline\"\n >\n <Icon\n name=\"icon-gui-x-mark-outline\"\n size=\"1.25rem\"\n color={textColor}\n />\n </button>\n )}\n </div>\n </div>\n );\n};\n\nexport default Notice;\n"],"names":["React","useEffect","Icon","cn","NoticeScripts","defaultTextColor","contentWrapperClasses","ContentWrapper","buttonLink","textColor","children","a","href","className","div","Notice","buttonLabel","bodyText","title","config","closeBtn","bgColor","bannerContainer","document","querySelector","cookieId","noticeId","options","collapse","data-id","style","maxHeight","overflow","strong","span","button","type","name","size","color"],"mappings":"AAAA,OAAOA,OAAoBC,SAAS,KAAQ,OAAQ,AAGpD,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,eAAgB,AAC/B,QAAOC,kBAAmB,uBAAwB,CAkClD,MAAMC,iBAAmB,mBAEzB,MAAMC,sBAAwB,qCAE9B,MAAMC,eAAiB,CAAC,CAAEC,UAAU,CAAEC,UAAYJ,gBAAgB,CAAEK,QAAQ,CAAuB,GACjGF,WACE,oBAACG,KAAEC,KAAMJ,WAAYK,UAAWV,GAAGG,sBAAuBG,YACvDC,UAGH,oBAACI,OAAID,UAAWV,GAAGG,sBAAuBG,YAAaC,UAG3D,MAAMK,OAAS,CAAC,CACdP,UAAU,CACVQ,WAAW,CACXC,QAAQ,CACRC,KAAK,CACLC,MAAM,CACNC,QAAQ,CACRC,QAAU,2BAA2B,CACrCZ,UAAYJ,gBAAgB,CAChB,IACZJ,UAAU,KACRG,cAAc,CACZkB,gBAAiBC,SAASC,aAAa,CAAC,yBACxCC,SAAUN,QAAQM,SAClBC,SAAUP,QAAQO,SAClBC,QAAS,CACPC,SAAUT,QAAQQ,SAASC,UAAY,KACzC,CACF,EACF,EAAG,EAAE,EAEL,OACE,oBAACd,OACCD,UAAWV,GAAG,kBAAmBkB,QAASZ,WAC1CoB,UAAQ,YACRC,MAAO,CAAEC,UAAW,EAAGC,SAAU,QAAS,GAE1C,oBAAClB,OAAID,UAAU,6DACb,oBAACN,gBAAeC,WAAYA,YAAc,KACxC,oBAACyB,UAAOpB,UAAU,oCAAoCK,OACtD,oBAACgB,QAAKrB,UAAU,QAAQI,UACvBD,aACC,oBAACkB,QAAKrB,UAAU,8CACbG,cAKNI,UACC,oBAACe,UACCC,KAAK,SACLvB,UAAU,uDAEV,oBAACX,MACCmC,KAAK,0BACLC,KAAK,UACLC,MAAO9B,cAOrB,CAEA,gBAAeM,MAAO"}
|
package/core/insights/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import*as mixpanel from"./mixpanel";import*as posthog from"./posthog";let debugMode=false;export const initInsights=({mixpanelToken,mixpanelAutoCapture,posthogApiKey,posthogApiHost,debug=false})=>{debugMode=!!debug;try{mixpanel.initMixpanel(mixpanelToken,mixpanelAutoCapture,debugMode)}catch(e){if(debugMode){console.error("Failed to initialize Mixpanel",e)}}try{posthog.initPosthog(posthogApiKey,posthogApiHost)}catch(e){if(debugMode){console.error("Failed to initialize Posthog",e)}}};export const enableDebugMode=()=>{debugMode=true;try{mixpanel.enableDebugMode();posthog.enableDebugMode()}catch(e){console.error("Failed to enable debug mode",e)}};export const disableDebugMode=()=>{debugMode=false;try{mixpanel.disableDebugMode();posthog.disableDebugMode()}catch(e){console.error("Failed to disable debug mode",e)}};export const identify=({userId,accountId,organisationId,email,name})=>{try{mixpanel.identify(userId,accountId,organisationId,email,name)}catch(e){if(debugMode){console.error("Failed to identify user in Mixpanel",e)}}try{posthog.identify(userId,accountId,organisationId,email,name)}catch(e){if(debugMode){console.error("Failed to identify user in Posthog",e)}}};export const trackPageView=()=>{try{mixpanel.trackPageView()}catch(e){if(debugMode){console.error("Failed to track page view in Mixpanel",e)}}try{posthog.trackPageView()}catch(e){if(debugMode){console.error("Failed to track page view in Posthog",e)}}};export const track=(event,properties)=>{try{mixpanel.track(event,properties)}catch(e){if(debugMode){console.error("Failed to track event in Mixpanel",e)}}try{posthog.track(event,properties)}catch(e){if(debugMode){console.error("Failed to track event in Posthog",e)}}};export const setupObserver=()=>{const getInsightAttributes=element=>{const MAX_ATTRIBUTES=10;let count=0;const attributes={};for(const attr of element.attributes){if(count>=MAX_ATTRIBUTES)break;if(attr.name.startsWith("data-insight-")){if(!/^data-insight-[a-zA-Z0-9-]+$/.test(attr.name))continue;if(typeof attr.value!=="string"||attr.value.length>100)continue;const key=attr.name.replace("data-insight-","").split("-").map((part,index)=>index===0?part:part.charAt(0).toUpperCase()+part.slice(1)).join("");attributes[key]=attr.value;count++}}return attributes};const findClosestElementWithInsights=element=>{let current=element;while(current&¤t!==document.body){const insights=getInsightAttributes(current);if(Object.keys(insights).length>0){return insights}current=current.parentElement}return null};const handleClick=event=>{if(!(event.target instanceof HTMLElement))return;const insights=findClosestElementWithInsights(event.target);if(insights){const{event:eventName,...properties}=insights;track(eventName||"element_clicked",properties)}};document.body.addEventListener("click",handleClick);return()=>{document.body.removeEventListener("click",handleClick)}};
|
|
1
|
+
import*as mixpanel from"./mixpanel";import*as posthog from"./posthog";let debugMode=false;export const initInsights=({mixpanelToken,mixpanelAutoCapture,posthogApiKey,posthogApiHost,debug=false})=>{debugMode=!!debug;try{mixpanel.initMixpanel(mixpanelToken,mixpanelAutoCapture,debugMode)}catch(e){if(debugMode){console.error("Failed to initialize Mixpanel",e)}}try{posthog.initPosthog(posthogApiKey,posthogApiHost)}catch(e){if(debugMode){console.error("Failed to initialize Posthog",e)}}};export const enableDebugMode=()=>{debugMode=true;try{mixpanel.enableDebugMode();posthog.enableDebugMode()}catch(e){console.error("Failed to enable debug mode",e)}};export const disableDebugMode=()=>{debugMode=false;try{mixpanel.disableDebugMode();posthog.disableDebugMode()}catch(e){console.error("Failed to disable debug mode",e)}};export const identify=({userId,accountId,organisationId,email,name})=>{if(!userId){if(debugMode){console.warn("User ID not provided, skipping identify")}return}try{mixpanel.identify({userId,accountId,organisationId,email,name})}catch(e){if(debugMode){console.error("Failed to identify user in Mixpanel",e)}}try{posthog.identify({userId,accountId,organisationId,email,name})}catch(e){if(debugMode){console.error("Failed to identify user in Posthog",e)}}};export const trackPageView=()=>{try{mixpanel.trackPageView()}catch(e){if(debugMode){console.error("Failed to track page view in Mixpanel",e)}}try{posthog.trackPageView()}catch(e){if(debugMode){console.error("Failed to track page view in Posthog",e)}}};export const track=(event,properties)=>{try{mixpanel.track(event,properties)}catch(e){if(debugMode){console.error("Failed to track event in Mixpanel",e)}}try{posthog.track(event,properties)}catch(e){if(debugMode){console.error("Failed to track event in Posthog",e)}}};export const setupObserver=()=>{const getInsightAttributes=element=>{const MAX_ATTRIBUTES=10;let count=0;const attributes={};for(const attr of element.attributes){if(count>=MAX_ATTRIBUTES)break;if(attr.name.startsWith("data-insight-")){if(!/^data-insight-[a-zA-Z0-9-]+$/.test(attr.name))continue;if(typeof attr.value!=="string"||attr.value.length>100)continue;const key=attr.name.replace("data-insight-","").split("-").map((part,index)=>index===0?part:part.charAt(0).toUpperCase()+part.slice(1)).join("");attributes[key]=attr.value;count++}}return attributes};const findClosestElementWithInsights=element=>{let current=element;while(current&¤t!==document.body){const insights=getInsightAttributes(current);if(Object.keys(insights).length>0){return insights}current=current.parentElement}return null};const handleClick=event=>{if(!(event.target instanceof HTMLElement))return;const insights=findClosestElementWithInsights(event.target);if(insights){const{event:eventName,...properties}=insights;track(eventName||"element_clicked",properties)}};document.body.addEventListener("click",handleClick);return()=>{document.body.removeEventListener("click",handleClick)}};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/insights/index.ts"],"sourcesContent":["import * as mixpanel from
|
|
1
|
+
{"version":3,"sources":["../../../src/core/insights/index.ts"],"sourcesContent":["import * as mixpanel from \"./mixpanel\";\nimport * as posthog from \"./posthog\";\nimport { InsightsIdentity } from \"./types\";\n\nexport type InsightsConfig = {\n debug: boolean;\n mixpanelToken: string;\n mixpanelAutoCapture: boolean;\n posthogApiKey: string;\n posthogApiHost: string;\n};\n\nlet debugMode = false;\n\nexport const initInsights = ({\n mixpanelToken,\n mixpanelAutoCapture,\n posthogApiKey,\n posthogApiHost,\n debug = false,\n}: InsightsConfig) => {\n debugMode = !!debug;\n\n try {\n mixpanel.initMixpanel(mixpanelToken, mixpanelAutoCapture, debugMode);\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to initialize Mixpanel\", e);\n }\n }\n\n try {\n posthog.initPosthog(posthogApiKey, posthogApiHost);\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to initialize Posthog\", e);\n }\n }\n};\n\nexport const enableDebugMode = () => {\n debugMode = true;\n try {\n mixpanel.enableDebugMode();\n posthog.enableDebugMode();\n } catch (e) {\n console.error(\"Failed to enable debug mode\", e);\n }\n};\n\nexport const disableDebugMode = () => {\n debugMode = false;\n try {\n mixpanel.disableDebugMode();\n posthog.disableDebugMode();\n } catch (e) {\n console.error(\"Failed to disable debug mode\", e);\n }\n};\n\nexport const identify = ({\n userId,\n accountId,\n organisationId,\n email,\n name,\n}: InsightsIdentity) => {\n // In very rare cases we might have a user without an account, so we'll\n // let null/undefined/blank strings through on that one\n if (!userId) {\n if (debugMode) {\n console.warn(\"User ID not provided, skipping identify\");\n }\n return;\n }\n\n try {\n mixpanel.identify({ userId, accountId, organisationId, email, name });\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to identify user in Mixpanel\", e);\n }\n }\n\n try {\n posthog.identify({ userId, accountId, organisationId, email, name });\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to identify user in Posthog\", e);\n }\n }\n};\n\nexport const trackPageView = () => {\n try {\n mixpanel.trackPageView();\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to track page view in Mixpanel\", e);\n }\n }\n\n try {\n posthog.trackPageView();\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to track page view in Posthog\", e);\n }\n }\n};\n\nexport const track = (event: string, properties?: Record<string, unknown>) => {\n try {\n mixpanel.track(event, properties);\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to track event in Mixpanel\", e);\n }\n }\n\n try {\n posthog.track(event, properties);\n } catch (e) {\n if (debugMode) {\n console.error(\"Failed to track event in Posthog\", e);\n }\n }\n};\n\ntype InsightAttributes = {\n event?: string;\n [key: string]: string | undefined;\n};\n\nexport const setupObserver = () => {\n // Helper to get all data-insight-* attributes from an element\n const getInsightAttributes = (element): InsightAttributes => {\n // limit how many data attributes we'll process\n const MAX_ATTRIBUTES = 10;\n let count = 0;\n\n const attributes: InsightAttributes = {};\n\n for (const attr of element.attributes) {\n if (count >= MAX_ATTRIBUTES) break;\n if (attr.name.startsWith(\"data-insight-\")) {\n // Validate attribute name format\n if (!/^data-insight-[a-zA-Z0-9-]+$/.test(attr.name)) continue;\n\n // Sanitize attribute value\n if (typeof attr.value !== \"string\" || attr.value.length > 100) continue;\n\n // Convert data-insight-event-name to eventName\n const key = attr.name\n .replace(\"data-insight-\", \"\")\n .split(\"-\")\n .map((part, index) =>\n index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1),\n )\n .join(\"\");\n attributes[key] = attr.value;\n count++;\n }\n }\n return attributes;\n };\n\n // Helper to find closest element with data-insight attributes\n const findClosestElementWithInsights = (element) => {\n let current = element;\n while (current && current !== document.body) {\n const insights = getInsightAttributes(current);\n if (Object.keys(insights).length > 0) {\n return insights;\n }\n current = current.parentElement;\n }\n return null;\n };\n\n // Global click handler\n const handleClick = (event: MouseEvent): void => {\n if (!(event.target instanceof HTMLElement)) return;\n const insights = findClosestElementWithInsights(event.target);\n if (insights) {\n // Extract special properties if they exist\n const { event: eventName, ...properties } = insights;\n track(eventName || \"element_clicked\", properties);\n }\n };\n\n // Add listener to document body to catch all clicks\n document.body.addEventListener(\"click\", handleClick);\n\n // Return cleanup function in case it's needed\n return () => {\n document.body.removeEventListener(\"click\", handleClick);\n };\n};\n"],"names":["mixpanel","posthog","debugMode","initInsights","mixpanelToken","mixpanelAutoCapture","posthogApiKey","posthogApiHost","debug","initMixpanel","e","console","error","initPosthog","enableDebugMode","disableDebugMode","identify","userId","accountId","organisationId","email","name","warn","trackPageView","track","event","properties","setupObserver","getInsightAttributes","element","MAX_ATTRIBUTES","count","attributes","attr","startsWith","test","value","length","key","replace","split","map","part","index","charAt","toUpperCase","slice","join","findClosestElementWithInsights","current","document","body","insights","Object","keys","parentElement","handleClick","target","HTMLElement","eventName","addEventListener","removeEventListener"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import mixpanel from"mixpanel-browser";export const initMixpanel=(token,autoCapture=false,debug=false)=>{const blockSelectors=["[ph-no-capture]",'[data-sl="mask"]'];if(!token){console.warn("Mixpanel token not provided, skipping initialization");return}mixpanel.init(token,{debug:debug,persistence:"localStorage",autocapture:autoCapture?{block_selectors:blockSelectors}:false,track_pageview:false})};export const enableDebugMode=()=>{mixpanel.set_config({debug:true})};export const disableDebugMode=()=>{mixpanel.set_config({debug:false})};export const identify=(userId,accountId,organisationId,email,name)=>{mixpanel.identify(userId);mixpanel.people.set({$email:email,$name:name})
|
|
1
|
+
import mixpanel from"mixpanel-browser";export const initMixpanel=(token,autoCapture=false,debug=false)=>{const blockSelectors=["[ph-no-capture]",'[data-sl="mask"]'];if(!token){console.warn("Mixpanel token not provided, skipping initialization");return}mixpanel.init(token,{debug:debug,persistence:"localStorage",autocapture:autoCapture?{block_selectors:blockSelectors}:false,track_pageview:false})};export const enableDebugMode=()=>{mixpanel.set_config({debug:true})};export const disableDebugMode=()=>{mixpanel.set_config({debug:false})};export const identify=({userId,accountId,organisationId,email,name})=>{if(!userId){return}mixpanel.identify(userId);if(email||name){mixpanel.people.set({$email:email,$name:name})}if(accountId){mixpanel.people.union({account_id:[accountId]})}if(organisationId){mixpanel.people.set({organisation_id:[organisationId]})}};export const trackPageView=mixpanel.track_pageview;export const track=mixpanel.track;
|
|
2
2
|
//# sourceMappingURL=mixpanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/insights/mixpanel.ts"],"sourcesContent":["import mixpanel from \"mixpanel-browser\";\n\nexport const initMixpanel = (\n token: string,\n autoCapture: boolean = false,\n debug: boolean = false,\n) => {\n const blockSelectors = [\"[ph-no-capture]\", '[data-sl=\"mask\"]'];\n if (!token) {\n console.warn(\"Mixpanel token not provided, skipping initialization\");\n return;\n }\n\n mixpanel.init(token, {\n debug: debug,\n persistence: \"localStorage\",\n autocapture: autoCapture\n ? {\n block_selectors: blockSelectors,\n }\n : false,\n track_pageview: false, // We'll track page views manually\n });\n};\n\nexport const enableDebugMode = () => {\n mixpanel.set_config({ debug: true });\n};\n\nexport const disableDebugMode = () => {\n mixpanel.set_config({ debug: false });\n};\n\nexport const identify = (\n userId
|
|
1
|
+
{"version":3,"sources":["../../../src/core/insights/mixpanel.ts"],"sourcesContent":["import mixpanel from \"mixpanel-browser\";\n\nimport { InsightsIdentity } from \"./types\";\n\nexport const initMixpanel = (\n token: string,\n autoCapture: boolean = false,\n debug: boolean = false,\n) => {\n const blockSelectors = [\"[ph-no-capture]\", '[data-sl=\"mask\"]'];\n if (!token) {\n console.warn(\"Mixpanel token not provided, skipping initialization\");\n return;\n }\n\n mixpanel.init(token, {\n debug: debug,\n persistence: \"localStorage\",\n autocapture: autoCapture\n ? {\n block_selectors: blockSelectors,\n }\n : false,\n track_pageview: false, // We'll track page views manually\n });\n};\n\nexport const enableDebugMode = () => {\n mixpanel.set_config({ debug: true });\n};\n\nexport const disableDebugMode = () => {\n mixpanel.set_config({ debug: false });\n};\n\nexport const identify = ({\n userId,\n accountId,\n organisationId,\n email,\n name,\n}: InsightsIdentity) => {\n // In very rare cases we might have a user without an account, so we'll\n // let null/undefined/blank strings through on that one\n if (!userId) {\n return;\n }\n\n mixpanel.identify(userId);\n\n if (email || name) {\n mixpanel.people.set({ $email: email, $name: name });\n }\n\n if (accountId) {\n mixpanel.people.union({ account_id: [accountId] });\n }\n\n if (organisationId) {\n mixpanel.people.set({ organisation_id: [organisationId] });\n }\n};\n\nexport const trackPageView = mixpanel.track_pageview;\n\nexport const track = mixpanel.track;\n"],"names":["mixpanel","initMixpanel","token","autoCapture","debug","blockSelectors","console","warn","init","persistence","autocapture","block_selectors","track_pageview","enableDebugMode","set_config","disableDebugMode","identify","userId","accountId","organisationId","email","name","people","set","$email","$name","union","account_id","organisation_id","trackPageView","track"],"mappings":"AAAA,OAAOA,aAAc,kBAAmB,AAIxC,QAAO,MAAMC,aAAe,CAC1BC,MACAC,YAAuB,KAAK,CAC5BC,MAAiB,KAAK,IAEtB,MAAMC,eAAiB,CAAC,kBAAmB,mBAAmB,CAC9D,GAAI,CAACH,MAAO,CACVI,QAAQC,IAAI,CAAC,wDACb,MACF,CAEAP,SAASQ,IAAI,CAACN,MAAO,CACnBE,MAAOA,MACPK,YAAa,eACbC,YAAaP,YACT,CACEQ,gBAAiBN,cACnB,EACA,MACJO,eAAgB,KAClB,EACF,CAAE,AAEF,QAAO,MAAMC,gBAAkB,KAC7Bb,SAASc,UAAU,CAAC,CAAEV,MAAO,IAAK,EACpC,CAAE,AAEF,QAAO,MAAMW,iBAAmB,KAC9Bf,SAASc,UAAU,CAAC,CAAEV,MAAO,KAAM,EACrC,CAAE,AAEF,QAAO,MAAMY,SAAW,CAAC,CACvBC,MAAM,CACNC,SAAS,CACTC,cAAc,CACdC,KAAK,CACLC,IAAI,CACa,IAGjB,GAAI,CAACJ,OAAQ,CACX,MACF,CAEAjB,SAASgB,QAAQ,CAACC,QAElB,GAAIG,OAASC,KAAM,CACjBrB,SAASsB,MAAM,CAACC,GAAG,CAAC,CAAEC,OAAQJ,MAAOK,MAAOJ,IAAK,EACnD,CAEA,GAAIH,UAAW,CACblB,SAASsB,MAAM,CAACI,KAAK,CAAC,CAAEC,WAAY,CAACT,UAAU,AAAC,EAClD,CAEA,GAAIC,eAAgB,CAClBnB,SAASsB,MAAM,CAACC,GAAG,CAAC,CAAEK,gBAAiB,CAACT,eAAe,AAAC,EAC1D,CACF,CAAE,AAEF,QAAO,MAAMU,cAAgB7B,SAASY,cAAc,AAAC,AAErD,QAAO,MAAMkB,MAAQ9B,SAAS8B,KAAK,AAAC"}
|
package/core/insights/posthog.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import posthog from"posthog-js";export const initPosthog=(apiKey,apiHost)=>{posthog.init(apiKey,{api_host:apiHost,capture_pageview:false})};export const enableDebugMode=()=>{posthog.debug()};export const disableDebugMode=()=>{posthog.debug(false)};export const identify=(userId,accountId,organisationId,email,name)=>{if(userId!==posthog.get_distinct_id()){posthog.identify(userId,{email,name})}posthog.group("account",accountId)
|
|
1
|
+
import posthog from"posthog-js";export const initPosthog=(apiKey,apiHost)=>{posthog.init(apiKey,{api_host:apiHost,capture_pageview:false})};export const enableDebugMode=()=>{posthog.debug()};export const disableDebugMode=()=>{posthog.debug(false)};export const identify=({userId,accountId,organisationId,email,name})=>{if(!userId){return}if(userId!==posthog.get_distinct_id()){posthog.identify(userId,{email,name})}if(accountId){posthog.group("account",accountId)}if(organisationId){posthog.group("organisation",organisationId)}};export const trackPageView=()=>{posthog.capture("$pageview")};export const track=(event,properties)=>{posthog.capture(event,properties)};
|
|
2
2
|
//# sourceMappingURL=posthog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/insights/posthog.ts"],"sourcesContent":["import posthog from \"posthog-js\";\n\nexport const initPosthog = (apiKey: string, apiHost: string) => {\n posthog.init(apiKey, {\n api_host: apiHost,\n capture_pageview: false,\n });\n};\n\nexport const enableDebugMode = () => {\n posthog.debug();\n};\n\nexport const disableDebugMode = () => {\n posthog.debug(false);\n};\n\nexport const identify = (\n userId
|
|
1
|
+
{"version":3,"sources":["../../../src/core/insights/posthog.ts"],"sourcesContent":["import posthog from \"posthog-js\";\n\nimport { InsightsIdentity } from \"./types\";\n\nexport const initPosthog = (apiKey: string, apiHost: string) => {\n posthog.init(apiKey, {\n api_host: apiHost,\n capture_pageview: false,\n });\n};\n\nexport const enableDebugMode = () => {\n posthog.debug();\n};\n\nexport const disableDebugMode = () => {\n posthog.debug(false);\n};\n\nexport const identify = ({\n userId,\n accountId,\n organisationId,\n email,\n name,\n}: InsightsIdentity) => {\n // In very rare cases we might have a user without an account, so we'll\n // let null/undefined/blank strings through on that one\n if (!userId) {\n return;\n }\n\n if (userId !== posthog.get_distinct_id()) {\n posthog.identify(userId, { email, name });\n }\n\n // Associate all events in this session with this account\n if (accountId) {\n posthog.group(\"account\", accountId);\n }\n\n // Associate all events in this session with this organisation (if available)\n if (organisationId) {\n posthog.group(\"organisation\", organisationId);\n }\n};\n\nexport const trackPageView = () => {\n posthog.capture(\"$pageview\");\n};\n\nexport const track = (event: string, properties?: Record<string, unknown>) => {\n posthog.capture(event, properties);\n};\n"],"names":["posthog","initPosthog","apiKey","apiHost","init","api_host","capture_pageview","enableDebugMode","debug","disableDebugMode","identify","userId","accountId","organisationId","email","name","get_distinct_id","group","trackPageView","capture","track","event","properties"],"mappings":"AAAA,OAAOA,YAAa,YAAa,AAIjC,QAAO,MAAMC,YAAc,CAACC,OAAgBC,WAC1CH,QAAQI,IAAI,CAACF,OAAQ,CACnBG,SAAUF,QACVG,iBAAkB,KACpB,EACF,CAAE,AAEF,QAAO,MAAMC,gBAAkB,KAC7BP,QAAQQ,KAAK,EACf,CAAE,AAEF,QAAO,MAAMC,iBAAmB,KAC9BT,QAAQQ,KAAK,CAAC,MAChB,CAAE,AAEF,QAAO,MAAME,SAAW,CAAC,CACvBC,MAAM,CACNC,SAAS,CACTC,cAAc,CACdC,KAAK,CACLC,IAAI,CACa,IAGjB,GAAI,CAACJ,OAAQ,CACX,MACF,CAEA,GAAIA,SAAWX,QAAQgB,eAAe,GAAI,CACxChB,QAAQU,QAAQ,CAACC,OAAQ,CAAEG,MAAOC,IAAK,EACzC,CAGA,GAAIH,UAAW,CACbZ,QAAQiB,KAAK,CAAC,UAAWL,UAC3B,CAGA,GAAIC,eAAgB,CAClBb,QAAQiB,KAAK,CAAC,eAAgBJ,eAChC,CACF,CAAE,AAEF,QAAO,MAAMK,cAAgB,KAC3BlB,QAAQmB,OAAO,CAAC,YAClB,CAAE,AAEF,QAAO,MAAMC,MAAQ,CAACC,MAAeC,cACnCtB,QAAQmB,OAAO,CAACE,MAAOC,WACzB,CAAE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/core/insights/types.ts"],"sourcesContent":["export type InsightsIdentity = {\n userId: string;\n accountId: string;\n organisationId?: string;\n email?: string;\n name?: string;\n};\n"],"names":[],"mappings":"AAAA,QAME"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isJsonResponse}from"./remote-data-util";const fetchBlogPosts=async(store,blogUrl)=>{try{if(!blogUrl){console.log(`Skipping fetching blog posts, invalid blogUrl: "${blogUrl}"`);return}const options={headers:{accept:"application/json"},cache:"no-cache"};if(
|
|
1
|
+
import{isJsonResponse}from"./remote-data-util";const fetchBlogPosts=async(store,blogUrl)=>{try{if(!blogUrl){console.log(`Skipping fetching blog posts, invalid blogUrl: "${blogUrl}"`);return}const options={headers:{accept:"application/json"},cache:"no-cache"};if(false){options.credentials="include"}const res=await fetch(blogUrl,options);if(isJsonResponse(res.headers.get("content-type"))){const payload=await res.json();store.dispatch({type:"blog/loaded",payload})}else{throw new Error("Blog posts url is not serving json")}}catch(e){console.warn("Could not fetch blog posts due to error:",e)}};const initialState={recent:null};const REDUCER_KEY="blogPosts";const reducerBlogPosts={[REDUCER_KEY]:(state=initialState,action)=>{switch(action.type){case"blog/loaded":return{...state,recent:action.payload};default:return state}}};const selectRecentBlogPosts=store=>store.getState()[REDUCER_KEY]?.recent;export{fetchBlogPosts,reducerBlogPosts,selectRecentBlogPosts};
|
|
2
2
|
//# sourceMappingURL=remote-blogs-posts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/remote-blogs-posts.js"],"sourcesContent":["/* global __ENABLE_FETCH_WITH_CREDENTIALS__ */\n\nimport { isJsonResponse } from \"./remote-data-util\";\n\nconst fetchBlogPosts = async (store, blogUrl) => {\n try {\n if (!blogUrl) {\n console.log(\n `Skipping fetching blog posts, invalid blogUrl: \"${blogUrl}\"`,\n );\n return;\n }\n\n const options = {\n headers: {\n accept: \"application/json\",\n },\n cache: \"no-cache\",\n };\n\n if (__ENABLE_FETCH_WITH_CREDENTIALS__) {\n options.credentials = \"include\";\n }\n\n const res = await fetch(blogUrl, options);\n\n if (isJsonResponse(res.headers.get(\"content-type\"))) {\n const payload = await res.json();\n store.dispatch({ type: \"blog/loaded\", payload });\n } else {\n throw new Error(\"Blog posts url is not serving json\");\n }\n } catch (e) {\n console.warn(\"Could not fetch blog posts due to error:\", e);\n }\n};\n\nconst initialState = { recent: null };\n\nconst REDUCER_KEY = \"blogPosts\";\n\nconst reducerBlogPosts = {\n [REDUCER_KEY]: (state = initialState, action) => {\n switch (action.type) {\n case \"blog/loaded\":\n return { ...state, recent: action.payload };\n default:\n return state;\n }\n },\n};\n\nconst selectRecentBlogPosts = (store) => store.getState()[REDUCER_KEY]?.recent;\n\nexport { fetchBlogPosts, reducerBlogPosts, selectRecentBlogPosts };\n"],"names":["isJsonResponse","fetchBlogPosts","store","blogUrl","console","log","options","headers","accept","cache","credentials","res","fetch","get","payload","json","dispatch","type","Error","e","warn","initialState","recent","REDUCER_KEY","reducerBlogPosts","state","action","selectRecentBlogPosts","getState"],"mappings":"AAEA,OAASA,cAAc,KAAQ,oBAAqB,CAEpD,MAAMC,eAAiB,MAAOC,MAAOC,WACnC,GAAI,CACF,GAAI,CAACA,QAAS,CACZC,QAAQC,GAAG,CACT,CAAC,gDAAgD,EAAEF,QAAQ,CAAC,CAAC,EAE/D,MACF,CAEA,MAAMG,QAAU,CACdC,QAAS,CACPC,OAAQ,kBACV,EACAC,MAAO,UACT,EAEA,GApBJ,
|
|
1
|
+
{"version":3,"sources":["../../src/core/remote-blogs-posts.js"],"sourcesContent":["/* global __ENABLE_FETCH_WITH_CREDENTIALS__ */\n\nimport { isJsonResponse } from \"./remote-data-util\";\n\nconst fetchBlogPosts = async (store, blogUrl) => {\n try {\n if (!blogUrl) {\n console.log(\n `Skipping fetching blog posts, invalid blogUrl: \"${blogUrl}\"`,\n );\n return;\n }\n\n const options = {\n headers: {\n accept: \"application/json\",\n },\n cache: \"no-cache\",\n };\n\n if (__ENABLE_FETCH_WITH_CREDENTIALS__) {\n options.credentials = \"include\";\n }\n\n const res = await fetch(blogUrl, options);\n\n if (isJsonResponse(res.headers.get(\"content-type\"))) {\n const payload = await res.json();\n store.dispatch({ type: \"blog/loaded\", payload });\n } else {\n throw new Error(\"Blog posts url is not serving json\");\n }\n } catch (e) {\n console.warn(\"Could not fetch blog posts due to error:\", e);\n }\n};\n\nconst initialState = { recent: null };\n\nconst REDUCER_KEY = \"blogPosts\";\n\nconst reducerBlogPosts = {\n [REDUCER_KEY]: (state = initialState, action) => {\n switch (action.type) {\n case \"blog/loaded\":\n return { ...state, recent: action.payload };\n default:\n return state;\n }\n },\n};\n\nconst selectRecentBlogPosts = (store) => store.getState()[REDUCER_KEY]?.recent;\n\nexport { fetchBlogPosts, reducerBlogPosts, selectRecentBlogPosts };\n"],"names":["isJsonResponse","fetchBlogPosts","store","blogUrl","console","log","options","headers","accept","cache","credentials","res","fetch","get","payload","json","dispatch","type","Error","e","warn","initialState","recent","REDUCER_KEY","reducerBlogPosts","state","action","selectRecentBlogPosts","getState"],"mappings":"AAEA,OAASA,cAAc,KAAQ,oBAAqB,CAEpD,MAAMC,eAAiB,MAAOC,MAAOC,WACnC,GAAI,CACF,GAAI,CAACA,QAAS,CACZC,QAAQC,GAAG,CACT,CAAC,gDAAgD,EAAEF,QAAQ,CAAC,CAAC,EAE/D,MACF,CAEA,MAAMG,QAAU,CACdC,QAAS,CACPC,OAAQ,kBACV,EACAC,MAAO,UACT,EAEA,GApBJ,MAoB2C,CACrCH,QAAQI,WAAW,CAAG,SACxB,CAEA,MAAMC,IAAM,MAAMC,MAAMT,QAASG,SAEjC,GAAIN,eAAeW,IAAIJ,OAAO,CAACM,GAAG,CAAC,iBAAkB,CACnD,MAAMC,QAAU,MAAMH,IAAII,IAAI,GAC9Bb,MAAMc,QAAQ,CAAC,CAAEC,KAAM,cAAeH,OAAQ,EAChD,KAAO,CACL,MAAM,IAAII,MAAM,qCAClB,CACF,CAAE,MAAOC,EAAG,CACVf,QAAQgB,IAAI,CAAC,2CAA4CD,EAC3D,CACF,EAEA,MAAME,aAAe,CAAEC,OAAQ,IAAK,EAEpC,MAAMC,YAAc,YAEpB,MAAMC,iBAAmB,CACvB,CAACD,YAAY,CAAE,CAACE,MAAQJ,YAAY,CAAEK,UACpC,OAAQA,OAAOT,IAAI,EACjB,IAAK,cACH,MAAO,CAAE,GAAGQ,KAAK,CAAEH,OAAQI,OAAOZ,OAAO,AAAC,CAC5C,SACE,OAAOW,KACX,CACF,CACF,EAEA,MAAME,sBAAwB,AAACzB,OAAUA,MAAM0B,QAAQ,EAAE,CAACL,YAAY,EAAED,MAExE,QAASrB,cAAc,CAAEuB,gBAAgB,CAAEG,qBAAqB,CAAG"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isJsonResponse}from"./remote-data-util";const NOT_FOUND_ERROR_CODE="not-found";const fetchSessionData=async(store,sessionUrl)=>{const sessionLoaded=(payload={})=>store.dispatch({type:"session/loaded",payload});try{if(!sessionUrl){console.log(`Skipping fetching session, invalid sessionUrl: "${sessionUrl}"`);sessionLoaded();return}const options={headers:{accept:"application/json"},cache:"no-cache"};if(
|
|
1
|
+
import{isJsonResponse}from"./remote-data-util";const NOT_FOUND_ERROR_CODE="not-found";const fetchSessionData=async(store,sessionUrl)=>{const sessionLoaded=(payload={})=>store.dispatch({type:"session/loaded",payload});try{if(!sessionUrl){console.log(`Skipping fetching session, invalid sessionUrl: "${sessionUrl}"`);sessionLoaded();return}const options={headers:{accept:"application/json"},cache:"no-cache"};if(false){options.credentials="include"}const res=await fetch(sessionUrl,options);const jsonResponse=isJsonResponse(res.headers.get("content-type"));if(!jsonResponse){throw new Error("Session endpoint is not serving json")}const payload=await res.json();if(payload.error===NOT_FOUND_ERROR_CODE){sessionLoaded()}else{sessionLoaded(payload)}}catch(e){sessionLoaded();console.warn("Could not fetch session data due to error:",e)}};const initialState={data:null};const REDUCER_KEY="session";const reducerSessionData={[REDUCER_KEY]:(state=initialState,action)=>{switch(action.type){case"session/loaded":return{...state,data:action.payload};default:return state}}};const selectSessionData=store=>store.getState()[REDUCER_KEY]?.data;export{fetchSessionData,reducerSessionData,selectSessionData};
|
|
2
2
|
//# sourceMappingURL=remote-session-data.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/remote-session-data.js"],"sourcesContent":["/* global __ENABLE_FETCH_WITH_CREDENTIALS__ */\n\n// Fetches current users session data\n// Assumes an authenticated session, so will only work when used on ably.com/ably.io\n\nimport { isJsonResponse } from \"./remote-data-util\";\n\nconst NOT_FOUND_ERROR_CODE = \"not-found\";\n\nconst fetchSessionData = async (store, sessionUrl) => {\n const sessionLoaded = (payload = {}) =>\n store.dispatch({ type: \"session/loaded\", payload });\n\n try {\n if (!sessionUrl) {\n console.log(\n `Skipping fetching session, invalid sessionUrl: \"${sessionUrl}\"`,\n );\n sessionLoaded();\n return;\n }\n\n const options = {\n headers: {\n accept: \"application/json\",\n },\n cache: \"no-cache\",\n };\n\n if (__ENABLE_FETCH_WITH_CREDENTIALS__) {\n options.credentials = \"include\";\n }\n\n const res = await fetch(sessionUrl, options);\n const jsonResponse = isJsonResponse(res.headers.get(\"content-type\"));\n\n if (!jsonResponse) {\n throw new Error(\"Session endpoint is not serving json\");\n }\n\n const payload = await res.json();\n\n if (payload.error === NOT_FOUND_ERROR_CODE) {\n sessionLoaded();\n } else {\n sessionLoaded(payload);\n }\n } catch (e) {\n sessionLoaded();\n console.warn(\"Could not fetch session data due to error:\", e);\n }\n};\n\nconst initialState = { data: null };\n\nconst REDUCER_KEY = \"session\";\n\nconst reducerSessionData = {\n [REDUCER_KEY]: (state = initialState, action) => {\n switch (action.type) {\n case \"session/loaded\":\n return { ...state, data: action.payload };\n default:\n return state;\n }\n },\n};\n\nconst selectSessionData = (store) => store.getState()[REDUCER_KEY]?.data;\n\nexport { fetchSessionData, reducerSessionData, selectSessionData };\n"],"names":["isJsonResponse","NOT_FOUND_ERROR_CODE","fetchSessionData","store","sessionUrl","sessionLoaded","payload","dispatch","type","console","log","options","headers","accept","cache","credentials","res","fetch","jsonResponse","get","Error","json","error","e","warn","initialState","data","REDUCER_KEY","reducerSessionData","state","action","selectSessionData","getState"],"mappings":"AAKA,OAASA,cAAc,KAAQ,oBAAqB,CAEpD,MAAMC,qBAAuB,YAE7B,MAAMC,iBAAmB,MAAOC,MAAOC,cACrC,MAAMC,cAAgB,CAACC,QAAU,CAAC,CAAC,GACjCH,MAAMI,QAAQ,CAAC,CAAEC,KAAM,iBAAkBF,OAAQ,GAEnD,GAAI,CACF,GAAI,CAACF,WAAY,CACfK,QAAQC,GAAG,CACT,CAAC,gDAAgD,EAAEN,WAAW,CAAC,CAAC,EAElEC,gBACA,MACF,CAEA,MAAMM,QAAU,CACdC,QAAS,CACPC,OAAQ,kBACV,EACAC,MAAO,UACT,EAEA,GA7BJ,
|
|
1
|
+
{"version":3,"sources":["../../src/core/remote-session-data.js"],"sourcesContent":["/* global __ENABLE_FETCH_WITH_CREDENTIALS__ */\n\n// Fetches current users session data\n// Assumes an authenticated session, so will only work when used on ably.com/ably.io\n\nimport { isJsonResponse } from \"./remote-data-util\";\n\nconst NOT_FOUND_ERROR_CODE = \"not-found\";\n\nconst fetchSessionData = async (store, sessionUrl) => {\n const sessionLoaded = (payload = {}) =>\n store.dispatch({ type: \"session/loaded\", payload });\n\n try {\n if (!sessionUrl) {\n console.log(\n `Skipping fetching session, invalid sessionUrl: \"${sessionUrl}\"`,\n );\n sessionLoaded();\n return;\n }\n\n const options = {\n headers: {\n accept: \"application/json\",\n },\n cache: \"no-cache\",\n };\n\n if (__ENABLE_FETCH_WITH_CREDENTIALS__) {\n options.credentials = \"include\";\n }\n\n const res = await fetch(sessionUrl, options);\n const jsonResponse = isJsonResponse(res.headers.get(\"content-type\"));\n\n if (!jsonResponse) {\n throw new Error(\"Session endpoint is not serving json\");\n }\n\n const payload = await res.json();\n\n if (payload.error === NOT_FOUND_ERROR_CODE) {\n sessionLoaded();\n } else {\n sessionLoaded(payload);\n }\n } catch (e) {\n sessionLoaded();\n console.warn(\"Could not fetch session data due to error:\", e);\n }\n};\n\nconst initialState = { data: null };\n\nconst REDUCER_KEY = \"session\";\n\nconst reducerSessionData = {\n [REDUCER_KEY]: (state = initialState, action) => {\n switch (action.type) {\n case \"session/loaded\":\n return { ...state, data: action.payload };\n default:\n return state;\n }\n },\n};\n\nconst selectSessionData = (store) => store.getState()[REDUCER_KEY]?.data;\n\nexport { fetchSessionData, reducerSessionData, selectSessionData };\n"],"names":["isJsonResponse","NOT_FOUND_ERROR_CODE","fetchSessionData","store","sessionUrl","sessionLoaded","payload","dispatch","type","console","log","options","headers","accept","cache","credentials","res","fetch","jsonResponse","get","Error","json","error","e","warn","initialState","data","REDUCER_KEY","reducerSessionData","state","action","selectSessionData","getState"],"mappings":"AAKA,OAASA,cAAc,KAAQ,oBAAqB,CAEpD,MAAMC,qBAAuB,YAE7B,MAAMC,iBAAmB,MAAOC,MAAOC,cACrC,MAAMC,cAAgB,CAACC,QAAU,CAAC,CAAC,GACjCH,MAAMI,QAAQ,CAAC,CAAEC,KAAM,iBAAkBF,OAAQ,GAEnD,GAAI,CACF,GAAI,CAACF,WAAY,CACfK,QAAQC,GAAG,CACT,CAAC,gDAAgD,EAAEN,WAAW,CAAC,CAAC,EAElEC,gBACA,MACF,CAEA,MAAMM,QAAU,CACdC,QAAS,CACPC,OAAQ,kBACV,EACAC,MAAO,UACT,EAEA,GA7BJ,MA6B2C,CACrCH,QAAQI,WAAW,CAAG,SACxB,CAEA,MAAMC,IAAM,MAAMC,MAAMb,WAAYO,SACpC,MAAMO,aAAelB,eAAegB,IAAIJ,OAAO,CAACO,GAAG,CAAC,iBAEpD,GAAI,CAACD,aAAc,CACjB,MAAM,IAAIE,MAAM,uCAClB,CAEA,MAAMd,QAAU,MAAMU,IAAIK,IAAI,GAE9B,GAAIf,QAAQgB,KAAK,GAAKrB,qBAAsB,CAC1CI,eACF,KAAO,CACLA,cAAcC,QAChB,CACF,CAAE,MAAOiB,EAAG,CACVlB,gBACAI,QAAQe,IAAI,CAAC,6CAA8CD,EAC7D,CACF,EAEA,MAAME,aAAe,CAAEC,KAAM,IAAK,EAElC,MAAMC,YAAc,UAEpB,MAAMC,mBAAqB,CACzB,CAACD,YAAY,CAAE,CAACE,MAAQJ,YAAY,CAAEK,UACpC,OAAQA,OAAOtB,IAAI,EACjB,IAAK,iBACH,MAAO,CAAE,GAAGqB,KAAK,CAAEH,KAAMI,OAAOxB,OAAO,AAAC,CAC1C,SACE,OAAOuB,KACX,CACF,CACF,EAEA,MAAME,kBAAoB,AAAC5B,OAAUA,MAAM6B,QAAQ,EAAE,CAACL,YAAY,EAAED,IAEpE,QAASxB,gBAAgB,CAAE0B,kBAAkB,CAAEG,iBAAiB,CAAG"}
|
package/index.d.ts
CHANGED
|
@@ -763,23 +763,26 @@ export type MeganavSessionState = {
|
|
|
763
763
|
href: string;
|
|
764
764
|
};
|
|
765
765
|
};
|
|
766
|
-
type
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
cookieId: string;
|
|
779
|
-
noticeId: string;
|
|
766
|
+
export type MeganavNoticeProps = {
|
|
767
|
+
props: {
|
|
768
|
+
title: string;
|
|
769
|
+
bodyText: string;
|
|
770
|
+
buttonLink: string;
|
|
771
|
+
buttonLabel: string;
|
|
772
|
+
closeBtn: boolean;
|
|
773
|
+
};
|
|
774
|
+
config: {
|
|
775
|
+
cookieId: string;
|
|
776
|
+
noticeId: string | number;
|
|
777
|
+
options: {
|
|
780
778
|
collapse: boolean;
|
|
781
779
|
};
|
|
782
780
|
};
|
|
781
|
+
};
|
|
782
|
+
type MeganavProps = {
|
|
783
|
+
paths?: MeganavPaths;
|
|
784
|
+
themeName: "white" | "black" | "transparentToWhite";
|
|
785
|
+
notice?: MeganavNoticeProps;
|
|
783
786
|
loginLink?: string;
|
|
784
787
|
urlBase?: string;
|
|
785
788
|
addSearchApiKey: string;
|
|
@@ -1043,19 +1046,22 @@ function Notice({ bannerContainer, cookieId, noticeId, options }: {
|
|
|
1043
1046
|
}
|
|
1044
1047
|
|
|
1045
1048
|
declare module '@ably/ui/core/Notice' {
|
|
1046
|
-
|
|
1049
|
+
import { ColorClass, ColorThemeSet } from "@ably/ui/core/styles/colors/types";
|
|
1050
|
+
export type NoticeProps = {
|
|
1047
1051
|
buttonLink?: string;
|
|
1048
1052
|
buttonLabel?: string;
|
|
1049
1053
|
bodyText?: string;
|
|
1050
1054
|
title?: string;
|
|
1051
1055
|
closeBtn?: boolean;
|
|
1052
1056
|
config?: {
|
|
1053
|
-
|
|
1054
|
-
|
|
1057
|
+
options: {
|
|
1058
|
+
collapse: boolean;
|
|
1059
|
+
};
|
|
1060
|
+
noticeId: string | number;
|
|
1055
1061
|
cookieId: string;
|
|
1056
1062
|
};
|
|
1057
1063
|
bgColor?: string;
|
|
1058
|
-
textColor?:
|
|
1064
|
+
textColor?: ColorClass | ColorThemeSet;
|
|
1059
1065
|
bannerContainer?: Element | null;
|
|
1060
1066
|
cookieId?: string;
|
|
1061
1067
|
noticeId?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ably/ui",
|
|
3
|
-
"version": "15.5.
|
|
3
|
+
"version": "15.5.1-dev.4c700e3d",
|
|
4
4
|
"description": "Home of the Ably design system library ([design.ably.com](https://design.ably.com)). It provides a showcase, development/test environment and a publishing pipeline for different distributables.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,47 +19,46 @@
|
|
|
19
19
|
"workerDirectory": "./public"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@storybook/addon-a11y": "^8.
|
|
23
|
-
"@storybook/addon-essentials": "^8.
|
|
24
|
-
"@storybook/addon-interactions": "^8.
|
|
25
|
-
"@storybook/addon-links": "^8.
|
|
26
|
-
"@storybook/blocks": "^8.
|
|
27
|
-
"@storybook/react-vite": "^8.
|
|
28
|
-
"@storybook/test": "^8.
|
|
29
|
-
"@storybook/test-runner": "^0.21.
|
|
22
|
+
"@storybook/addon-a11y": "^8.6.0",
|
|
23
|
+
"@storybook/addon-essentials": "^8.6.0",
|
|
24
|
+
"@storybook/addon-interactions": "^8.6.0",
|
|
25
|
+
"@storybook/addon-links": "^8.6.0",
|
|
26
|
+
"@storybook/blocks": "^8.6.0",
|
|
27
|
+
"@storybook/react-vite": "^8.6.0",
|
|
28
|
+
"@storybook/test": "^8.6.0",
|
|
29
|
+
"@storybook/test-runner": "^0.21.3",
|
|
30
30
|
"@swc/cli": "^0.6.0",
|
|
31
31
|
"@swc/core": "^1.4.11",
|
|
32
32
|
"@tailwindcss/container-queries": "^0.1.1",
|
|
33
|
-
"@types/dompurify": "^3.0.5",
|
|
34
33
|
"@types/js-cookie": "^3.0.6",
|
|
35
34
|
"@types/lodash.throttle": "^4.1.9",
|
|
36
35
|
"@types/react-dom": "^18.3.0",
|
|
37
36
|
"@types/svg-sprite": "^0.0.39",
|
|
38
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
39
|
-
"@typescript-eslint/parser": "^8.
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
|
38
|
+
"@typescript-eslint/parser": "^8.25.0",
|
|
40
39
|
"@vitejs/plugin-react": "^4.2.1",
|
|
41
40
|
"@whitespace/storybook-addon-html": "^6.1.1",
|
|
42
41
|
"autoprefixer": "^10.0.2",
|
|
43
42
|
"eslint": "^8.57.0",
|
|
44
43
|
"eslint-config-prettier": "^10.0.1",
|
|
45
44
|
"eslint-plugin-react": "^7.34.3",
|
|
46
|
-
"eslint-plugin-storybook": "^0.11.
|
|
45
|
+
"eslint-plugin-storybook": "^0.11.3",
|
|
47
46
|
"heroicons": "^2.2.0",
|
|
48
47
|
"http-server": "14.1.1",
|
|
49
48
|
"mixpanel-browser": "^2.60.0",
|
|
50
|
-
"msw": "2.7.
|
|
49
|
+
"msw": "2.7.1",
|
|
51
50
|
"msw-storybook-addon": "^2.0.2",
|
|
52
51
|
"playwright": "^1.49.1",
|
|
53
52
|
"posthog-js": "^1.217.4",
|
|
54
53
|
"prettier": "^3.2.5",
|
|
55
54
|
"react-syntax-highlighter": "^15.6.1",
|
|
56
|
-
"storybook": "^8.
|
|
55
|
+
"storybook": "^8.6.0",
|
|
57
56
|
"storybook-dark-mode": "^4.0.2",
|
|
58
57
|
"svg-sprite": "^2.0.4",
|
|
59
58
|
"tailwindcss": "^3.3.6",
|
|
60
59
|
"ts-node": "^10.9.2",
|
|
61
60
|
"typescript": "5.7.3",
|
|
62
|
-
"vite": "^6.
|
|
61
|
+
"vite": "^6.2.0"
|
|
63
62
|
},
|
|
64
63
|
"scripts": {
|
|
65
64
|
"build:prebuild": "rm -rf core reset && mkdir -p dist/core",
|
|
@@ -78,8 +77,8 @@
|
|
|
78
77
|
"start": "vite --port 5000",
|
|
79
78
|
"storybook": "yarn build && storybook dev -p 6006",
|
|
80
79
|
"build-storybook": "yarn build && storybook build --quiet -o preview",
|
|
81
|
-
"test": "npx concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn build-storybook
|
|
82
|
-
"test:update-snapshots": "npx concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn build-storybook
|
|
80
|
+
"test": "npx concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn build-storybook && yarn http-server preview --port 6007 --silent\" \"wait-on tcp:6007 && yarn test-storybook --url http://127.0.0.1:6007\"",
|
|
81
|
+
"test:update-snapshots": "npx concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn build-storybook && yarn http-server preview --port 6007 --silent\" \"wait-on tcp:6007 && yarn test-storybook -u --url http://127.0.0.1:6007\""
|
|
83
82
|
},
|
|
84
83
|
"dependencies": {
|
|
85
84
|
"@radix-ui/react-accordion": "^1.2.1",
|
|
@@ -89,7 +88,7 @@
|
|
|
89
88
|
"addsearch-js-client": "^1.0.2",
|
|
90
89
|
"array-flat-polyfill": "^1.0.1",
|
|
91
90
|
"clsx": "^2.1.1",
|
|
92
|
-
"dompurify": "^3.
|
|
91
|
+
"dompurify": "^3.2.4",
|
|
93
92
|
"highlight.js": "^11.9.0",
|
|
94
93
|
"highlightjs-curl": "^1.3.0",
|
|
95
94
|
"js-cookie": "^3.0.5",
|