@ably/ui 17.8.0-dev.becb7c12 → 17.8.0

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/Badge.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/Badge.tsx"],"sourcesContent":["import React, { PropsWithChildren, useMemo } from \"react\";\nimport { IconName, IconSize } from \"./Icon/types\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn\";\nimport { ColorClassColorGroups } from \"./styles/colors/types\";\n\n/**\n * Props for the Badge component.\n */\ninterface BadgeProps {\n /**\n * The size of the badge. Can be one of \"xs\", \"sm\", \"md\", or \"lg\".\n */\n size?: \"xs\" | \"sm\" | \"md\" | \"lg\";\n\n /**\n * The color of the badge. Can be a value from ColorClassColorGroups or \"red\".\n */\n color?: ColorClassColorGroups | \"red\";\n\n /**\n * The name of the icon to be displayed before the children in the badge.\n */\n iconBefore?: IconName;\n\n /**\n * The name of the icon to be displayed after the children in the badge.\n */\n iconAfter?: IconName;\n\n /**\n * Additional CSS class names to apply to the badge.\n */\n className?: string;\n\n /**\n * Whether the badge is disabled. Defaults to false.\n */\n disabled?: boolean;\n\n /**\n * Whether the badge is focusable. Defaults to false.\n */\n focusable?: boolean;\n\n /**\n * Whether the badge is hoverable. Defaults to false.\n */\n hoverable?: boolean;\n\n /**\n * The size of the icons in the badge. Defaults to 12px.\n */\n iconSize?: IconSize;\n\n /**\n * Accessible label for the badge when interactive\n */\n ariaLabel?: string;\n\n /**\n * Additional CSS class names to apply to the children of the badge.\n */\n childClassName?: string;\n}\n\nconst Badge: React.FC<PropsWithChildren<BadgeProps>> = ({\n size = \"md\",\n color = \"neutral\",\n iconBefore,\n iconAfter,\n className,\n childClassName,\n children,\n disabled = false,\n focusable = false,\n hoverable = false,\n iconSize = \"12px\",\n ariaLabel,\n}) => {\n const sizeClass = useMemo(() => {\n switch (size) {\n case \"xs\":\n return \"px-2 py-0 text-[10px] leading-tight\";\n case \"sm\":\n return \"px-2 py-0.5 text-[10px] leading-tight\";\n case \"md\":\n return \"px-2.5 py-0.5 text-[11px] leading-normal\";\n case \"lg\":\n return \"px-3 py-[0.1875rem] text-[12px] leading-normal\";\n }\n }, [size]);\n\n const childClass = useMemo(() => {\n switch (size) {\n case \"xs\":\n case \"sm\":\n return \"leading-[18px]\";\n case \"md\":\n case \"lg\":\n return \"leading-[20px]\";\n }\n }, [size]);\n\n const colorClass = useMemo(() => {\n switch (color) {\n case \"neutral\":\n return \"text-neutral-900 dark:text-neutral-400\";\n case \"violet\":\n return \"text-violet-400\";\n case \"orange\":\n return \"text-orange-600\";\n case \"yellow\":\n return \"text-yellow-600\";\n case \"green\":\n return \"text-green-600\";\n case \"blue\":\n return \"text-blue-600\";\n case \"pink\":\n return \"text-pink-600\";\n case \"red\":\n return \"text-orange-700\";\n }\n }, [color]);\n\n return (\n <div\n className={cn(\n \"inline-flex bg-neutral-100 dark:bg-neutral-1200 rounded-2xl gap-1 items-center focus-base transition-colors select-none font-semibold\",\n sizeClass,\n colorClass,\n { \"focus-base\": focusable },\n {\n \"hover:bg-neutral-300 hover:dark:bg-neutral-1000 active:bg-neutral-300 dark:active:bg-neutral-1000\":\n hoverable,\n },\n {\n \"cursor-not-allowed disabled:text-gui-unavailable dark:disabled:text-gui-unavailable-dark\":\n disabled,\n },\n className,\n )}\n tabIndex={focusable ? 0 : undefined}\n role={focusable ? \"button\" : undefined}\n aria-label={focusable || hoverable ? ariaLabel : undefined}\n >\n {iconBefore ? (\n <Icon name={iconBefore} size={iconSize} color={colorClass} />\n ) : null}\n <span\n className={cn(\n \"whitespace-nowrap tracking-[0.04em]\",\n childClass,\n childClassName,\n )}\n >\n {children}\n </span>\n {iconAfter ? (\n <Icon name={iconAfter} size={iconSize} color={colorClass} />\n ) : null}\n </div>\n );\n};\n\nexport default Badge;\n"],"names":["React","useMemo","Icon","cn","Badge","size","color","iconBefore","iconAfter","className","childClassName","children","disabled","focusable","hoverable","iconSize","ariaLabel","sizeClass","childClass","colorClass","div","tabIndex","undefined","role","aria-label","name","span"],"mappings":"AAAA,OAAOA,OAA4BC,OAAO,KAAQ,OAAQ,AAE1D,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,YAAa,CA+D5B,MAAMC,MAAiD,CAAC,CACtDC,KAAO,IAAI,CACXC,MAAQ,SAAS,CACjBC,UAAU,CACVC,SAAS,CACTC,SAAS,CACTC,cAAc,CACdC,QAAQ,CACRC,SAAW,KAAK,CAChBC,UAAY,KAAK,CACjBC,UAAY,KAAK,CACjBC,SAAW,MAAM,CACjBC,SAAS,CACV,IACC,MAAMC,UAAYhB,QAAQ,KACxB,OAAQI,MACN,IAAK,KACH,MAAO,qCACT,KAAK,KACH,MAAO,uCACT,KAAK,KACH,MAAO,0CACT,KAAK,KACH,MAAO,gDACX,CACF,EAAG,CAACA,KAAK,EAET,MAAMa,WAAajB,QAAQ,KACzB,OAAQI,MACN,IAAK,KACL,IAAK,KACH,MAAO,gBACT,KAAK,KACL,IAAK,KACH,MAAO,gBACX,CACF,EAAG,CAACA,KAAK,EAET,MAAMc,WAAalB,QAAQ,KACzB,OAAQK,OACN,IAAK,UACH,MAAO,wCACT,KAAK,SACH,MAAO,iBACT,KAAK,SACH,MAAO,iBACT,KAAK,SACH,MAAO,iBACT,KAAK,QACH,MAAO,gBACT,KAAK,OACH,MAAO,eACT,KAAK,OACH,MAAO,eACT,KAAK,MACH,MAAO,iBACX,CACF,EAAG,CAACA,MAAM,EAEV,OACE,oBAACc,OACCX,UAAWN,GACT,wIACAc,UACAE,WACA,CAAE,aAAcN,SAAU,EAC1B,CACE,oGACEC,SACJ,EACA,CACE,2FACEF,QACJ,EACAH,WAEFY,SAAUR,UAAY,EAAIS,UAC1BC,KAAMV,UAAY,SAAWS,UAC7BE,aAAYX,WAAaC,UAAYE,UAAYM,WAEhDf,WACC,oBAACL,MAAKuB,KAAMlB,WAAYF,KAAMU,SAAUT,MAAOa,aAC7C,KACJ,oBAACO,QACCjB,UAAWN,GACT,sCACAe,WACAR,iBAGDC,UAEFH,UACC,oBAACN,MAAKuB,KAAMjB,UAAWH,KAAMU,SAAUT,MAAOa,aAC5C,KAGV,CAEA,gBAAef,KAAM"}
1
+ {"version":3,"sources":["../../src/core/Badge.tsx"],"sourcesContent":["import React, { PropsWithChildren, useMemo } from \"react\";\nimport { IconName, IconSize } from \"./Icon/types\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn\";\nimport { ColorClassColorGroups } from \"./styles/colors/types\";\n\n/**\n * Props for the Badge component.\n */\nexport interface BadgeProps {\n /**\n * The size of the badge. Can be one of \"xs\", \"sm\", \"md\", or \"lg\".\n */\n size?: \"xs\" | \"sm\" | \"md\" | \"lg\";\n\n /**\n * The color of the badge. Can be a value from ColorClassColorGroups or \"red\".\n */\n color?: ColorClassColorGroups | \"red\";\n\n /**\n * The name of the icon to be displayed before the children in the badge.\n */\n iconBefore?: IconName;\n\n /**\n * The name of the icon to be displayed after the children in the badge.\n */\n iconAfter?: IconName;\n\n /**\n * Additional CSS class names to apply to the badge.\n */\n className?: string;\n\n /**\n * Whether the badge is disabled. Defaults to false.\n */\n disabled?: boolean;\n\n /**\n * Whether the badge is focusable. Defaults to false.\n */\n focusable?: boolean;\n\n /**\n * Whether the badge is hoverable. Defaults to false.\n */\n hoverable?: boolean;\n\n /**\n * The size of the icons in the badge. Defaults to 12px.\n */\n iconSize?: IconSize;\n\n /**\n * Accessible label for the badge when interactive\n */\n ariaLabel?: string;\n\n /**\n * Additional CSS class names to apply to the children of the badge.\n */\n childClassName?: string;\n}\n\nconst Badge: React.FC<PropsWithChildren<BadgeProps>> = ({\n size = \"md\",\n color = \"neutral\",\n iconBefore,\n iconAfter,\n className,\n childClassName,\n children,\n disabled = false,\n focusable = false,\n hoverable = false,\n iconSize = \"12px\",\n ariaLabel,\n}) => {\n const sizeClass = useMemo(() => {\n switch (size) {\n case \"xs\":\n return \"px-2 py-0 text-[10px] leading-tight\";\n case \"sm\":\n return \"px-2 py-0.5 text-[10px] leading-tight\";\n case \"md\":\n return \"px-2.5 py-0.5 text-[11px] leading-normal\";\n case \"lg\":\n return \"px-3 py-[0.1875rem] text-[12px] leading-normal\";\n }\n }, [size]);\n\n const childClass = useMemo(() => {\n switch (size) {\n case \"xs\":\n case \"sm\":\n return \"leading-[18px]\";\n case \"md\":\n case \"lg\":\n return \"leading-[20px]\";\n }\n }, [size]);\n\n const colorClass = useMemo(() => {\n switch (color) {\n case \"neutral\":\n return \"text-neutral-900 dark:text-neutral-400\";\n case \"violet\":\n return \"text-violet-400\";\n case \"orange\":\n return \"text-orange-600\";\n case \"yellow\":\n return \"text-yellow-600\";\n case \"green\":\n return \"text-green-600\";\n case \"blue\":\n return \"text-blue-600\";\n case \"pink\":\n return \"text-pink-600\";\n case \"red\":\n return \"text-orange-700\";\n }\n }, [color]);\n\n return (\n <div\n className={cn(\n \"inline-flex bg-neutral-100 dark:bg-neutral-1200 rounded-2xl gap-1 items-center focus-base transition-colors select-none font-semibold\",\n sizeClass,\n colorClass,\n { \"focus-base\": focusable },\n {\n \"hover:bg-neutral-300 hover:dark:bg-neutral-1000 active:bg-neutral-300 dark:active:bg-neutral-1000\":\n hoverable,\n },\n {\n \"cursor-not-allowed disabled:text-gui-unavailable dark:disabled:text-gui-unavailable-dark\":\n disabled,\n },\n className,\n )}\n tabIndex={focusable ? 0 : undefined}\n role={focusable ? \"button\" : undefined}\n aria-label={focusable || hoverable ? ariaLabel : undefined}\n >\n {iconBefore ? (\n <Icon name={iconBefore} size={iconSize} color={colorClass} />\n ) : null}\n <span\n className={cn(\n \"whitespace-nowrap tracking-[0.04em]\",\n childClass,\n childClassName,\n )}\n >\n {children}\n </span>\n {iconAfter ? (\n <Icon name={iconAfter} size={iconSize} color={colorClass} />\n ) : null}\n </div>\n );\n};\n\nexport default Badge;\n"],"names":["React","useMemo","Icon","cn","Badge","size","color","iconBefore","iconAfter","className","childClassName","children","disabled","focusable","hoverable","iconSize","ariaLabel","sizeClass","childClass","colorClass","div","tabIndex","undefined","role","aria-label","name","span"],"mappings":"AAAA,OAAOA,OAA4BC,OAAO,KAAQ,OAAQ,AAE1D,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,YAAa,CA+D5B,MAAMC,MAAiD,CAAC,CACtDC,KAAO,IAAI,CACXC,MAAQ,SAAS,CACjBC,UAAU,CACVC,SAAS,CACTC,SAAS,CACTC,cAAc,CACdC,QAAQ,CACRC,SAAW,KAAK,CAChBC,UAAY,KAAK,CACjBC,UAAY,KAAK,CACjBC,SAAW,MAAM,CACjBC,SAAS,CACV,IACC,MAAMC,UAAYhB,QAAQ,KACxB,OAAQI,MACN,IAAK,KACH,MAAO,qCACT,KAAK,KACH,MAAO,uCACT,KAAK,KACH,MAAO,0CACT,KAAK,KACH,MAAO,gDACX,CACF,EAAG,CAACA,KAAK,EAET,MAAMa,WAAajB,QAAQ,KACzB,OAAQI,MACN,IAAK,KACL,IAAK,KACH,MAAO,gBACT,KAAK,KACL,IAAK,KACH,MAAO,gBACX,CACF,EAAG,CAACA,KAAK,EAET,MAAMc,WAAalB,QAAQ,KACzB,OAAQK,OACN,IAAK,UACH,MAAO,wCACT,KAAK,SACH,MAAO,iBACT,KAAK,SACH,MAAO,iBACT,KAAK,SACH,MAAO,iBACT,KAAK,QACH,MAAO,gBACT,KAAK,OACH,MAAO,eACT,KAAK,OACH,MAAO,eACT,KAAK,MACH,MAAO,iBACX,CACF,EAAG,CAACA,MAAM,EAEV,OACE,oBAACc,OACCX,UAAWN,GACT,wIACAc,UACAE,WACA,CAAE,aAAcN,SAAU,EAC1B,CACE,oGACEC,SACJ,EACA,CACE,2FACEF,QACJ,EACAH,WAEFY,SAAUR,UAAY,EAAIS,UAC1BC,KAAMV,UAAY,SAAWS,UAC7BE,aAAYX,WAAaC,UAAYE,UAAYM,WAEhDf,WACC,oBAACL,MAAKuB,KAAMlB,WAAYF,KAAMU,SAAUT,MAAOa,aAC7C,KACJ,oBAACO,QACCjB,UAAWN,GACT,sCACAe,WACAR,iBAGDC,UAEFH,UACC,oBAACN,MAAKuB,KAAMjB,UAAWH,KAAMU,SAAUT,MAAOa,aAC5C,KAGV,CAEA,gBAAef,KAAM"}
@@ -0,0 +1,2 @@
1
+ import{useCallback,useMemo}from"react";import Badge from"./Badge";import FeaturedLink from"./FeaturedLink";import Icon from"./Icon";import cn from"./utils/cn";const ContentTile=({title,className,description,cta,feature,featureType="image",featureIcons,centerFeature,badges,onClick,featureClassName,titleClassName,descriptionClassName,ctaClassName})=>{const handleClick=useCallback(()=>{if(!cta)return;if(onClick){onClick(cta.url)}else{window.location.href=cta.url}},[onClick,cta]);const renderedFeature=useMemo(()=>{if(!feature)return null;if(featureType==="image"){return React.createElement("div",{className:cn("content-tile__feature relative p-3 h-[200px] pb-0 flex items-end justify-center overflow-hidden rounded-lg bg-neutral-100 dark:bg-neutral-1200 border border-neutral-300 dark:border-neutral-1000 transition-[border-color,height]",centerFeature&&"items-center pb-3",cta&&"group-hover/content-tile:border-neutral-500 dark:group-hover/content-tile:border-neutral-800",featureClassName)},React.createElement("div",{className:cn("flex justify-center max-h-[200px]",!centerFeature&&"pt-6 [&_img]:min-w-max [&_img]:h-[200px]")},feature),featureIcons&&featureIcons?.length>0&&React.createElement("div",{className:"absolute bottom-3 right-3 flex gap-1.5 bg-neutral-000 dark:bg-neutral-1300 rounded border border-neutral-200 dark:border-neutral-1100 px-2 py-1.5"},featureIcons.map((icon,idx)=>React.createElement(Icon,{key:icon+idx,name:icon,size:"18px"}))))}if(featureType==="icon"){return React.createElement("div",{className:cn("h-9",featureClassName)},typeof feature==="string"?React.createElement(Icon,{name:feature,size:"36px"}):feature)}return null},[centerFeature,cta,feature,featureClassName,featureIcons,featureType]);return React.createElement("div",{className:cn("group/content-tile",cta&&"cursor-pointer",className),...cta&&{onClick:handleClick,onKeyDown:e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();handleClick()}},tabIndex:0,role:"link","aria-label":title}},renderedFeature,React.createElement("div",{className:"content-tile__content pr-4"},title&&React.createElement("h2",{className:cn("content-tile__title mt-4 mb-2 ui-text-h4 text-neutral-1300 dark:text-neutral-000",titleClassName)},title),description&&React.createElement("div",{className:cn("content-tile__description mb-2 ui-text-p2 text-neutral-800 dark:text-neutral-500 group-hover/content-tile:text-neutral-1000 dark:group-hover/content-tile:text-neutral-300 transition-colors",descriptionClassName)},description),badges&&badges.length>0&&React.createElement("div",{className:"content-tile__badges mb-2 flex flex-wrap gap-2"},badges.map(({label,className,...badgeProps},idx)=>React.createElement(Badge,{key:label+idx,className:cn("uppercase text-[10px]",className),...badgeProps},label))),cta&&!cta.implicit&&React.createElement(FeaturedLink,{url:"#",additionalCSS:cn("pt-0 pointer-events-none font-medium items-center text-neutral-800 dark:text-neutral-500 group-hover/content-tile:text-neutral-1300 dark:group-hover/content-tile:text-neutral-000 transition-colors [&_svg]:group-hover/content-tile:left-0",ctaClassName),iconColor:"text-orange-600"},cta.text)))};export default ContentTile;
2
+ //# sourceMappingURL=ContentTile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/ContentTile.tsx"],"sourcesContent":["import type React from \"react\";\nimport { useCallback, useMemo } from \"react\";\nimport Badge, { type BadgeProps } from \"./Badge\";\nimport FeaturedLink from \"./FeaturedLink\";\nimport Icon from \"./Icon\";\nimport type { IconName } from \"./Icon/types\";\nimport cn from \"./utils/cn\";\n\ntype ContentTileProps = {\n /** The title text to display */\n title?: string;\n /** Additional CSS classes for the root container */\n className?: string;\n /** The description text to display */\n description?: string;\n /**\n * Call-to-action configuration.\n * - text: The CTA button or link text.\n * - url: The destination URL for the CTA.\n * - implicit: If true, no explicit CTA button is shown.\n */\n cta?: {\n text: string;\n url: string;\n implicit?: boolean;\n };\n /** Content to display in the feature area (image or icon) */\n feature?: React.ReactNode | string;\n /** Type of feature to render - either 'image' or 'icon' */\n featureType?: \"image\" | \"icon\";\n /** Array of icon names to display as overlays on the feature */\n featureIcons?: IconName[];\n /** Whether to vertically center the feature content */\n centerFeature?: boolean;\n /** Array of badges to display */\n badges?: (BadgeProps & { label: string })[];\n /** Custom click handler, receives the CTA URL if present */\n onClick?: (url?: string) => void;\n /** Additional CSS classes for the feature element */\n featureClassName?: string;\n /** Additional CSS classes for the title element */\n titleClassName?: string;\n /** Additional CSS classes for the description element */\n descriptionClassName?: string;\n /** Additional CSS classes for the CTA element */\n ctaClassName?: string;\n};\n\nconst ContentTile: React.FC<ContentTileProps> = ({\n title,\n className,\n description,\n cta,\n feature,\n featureType = \"image\",\n featureIcons,\n centerFeature,\n badges,\n onClick,\n featureClassName,\n titleClassName,\n descriptionClassName,\n ctaClassName,\n}) => {\n const handleClick = useCallback(() => {\n if (!cta) return;\n\n if (onClick) {\n onClick(cta.url);\n } else {\n window.location.href = cta.url;\n }\n }, [onClick, cta]);\n\n const renderedFeature = useMemo(() => {\n if (!feature) return null;\n\n if (featureType === \"image\") {\n return (\n <div\n className={cn(\n \"content-tile__feature relative p-3 h-[200px] pb-0 flex items-end justify-center overflow-hidden rounded-lg bg-neutral-100 dark:bg-neutral-1200 border border-neutral-300 dark:border-neutral-1000 transition-[border-color,height]\",\n centerFeature && \"items-center pb-3\",\n cta &&\n \"group-hover/content-tile:border-neutral-500 dark:group-hover/content-tile:border-neutral-800\",\n featureClassName,\n )}\n >\n <div\n className={cn(\n \"flex justify-center max-h-[200px]\",\n !centerFeature && \"pt-6 [&_img]:min-w-max [&_img]:h-[200px]\",\n )}\n >\n {feature}\n </div>\n {featureIcons && featureIcons?.length > 0 && (\n <div className=\"absolute bottom-3 right-3 flex gap-1.5 bg-neutral-000 dark:bg-neutral-1300 rounded border border-neutral-200 dark:border-neutral-1100 px-2 py-1.5\">\n {featureIcons.map((icon, idx) => (\n <Icon key={icon + idx} name={icon} size=\"18px\" />\n ))}\n </div>\n )}\n </div>\n );\n }\n\n if (featureType === \"icon\") {\n return (\n <div className={cn(\"h-9\", featureClassName)}>\n {typeof feature === \"string\" ? (\n <Icon name={feature as IconName} size=\"36px\" />\n ) : (\n feature\n )}\n </div>\n );\n }\n\n return null;\n }, [\n centerFeature,\n cta,\n feature,\n featureClassName,\n featureIcons,\n featureType,\n ]);\n\n return (\n <div\n className={cn(\"group/content-tile\", cta && \"cursor-pointer\", className)}\n {...(cta && {\n onClick: handleClick,\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleClick();\n }\n },\n tabIndex: 0,\n role: \"link\",\n \"aria-label\": title,\n })}\n >\n {renderedFeature}\n <div className=\"content-tile__content pr-4\">\n {title && (\n <h2\n className={cn(\n \"content-tile__title mt-4 mb-2 ui-text-h4 text-neutral-1300 dark:text-neutral-000\",\n titleClassName,\n )}\n >\n {title}\n </h2>\n )}\n {description && (\n <div\n className={cn(\n \"content-tile__description mb-2 ui-text-p2 text-neutral-800 dark:text-neutral-500 group-hover/content-tile:text-neutral-1000 dark:group-hover/content-tile:text-neutral-300 transition-colors\",\n descriptionClassName,\n )}\n >\n {description}\n </div>\n )}\n {badges && badges.length > 0 && (\n <div className=\"content-tile__badges mb-2 flex flex-wrap gap-2\">\n {badges.map(({ label, className, ...badgeProps }, idx) => (\n <Badge\n key={label + idx}\n className={cn(\"uppercase text-[10px]\", className)}\n {...badgeProps}\n >\n {label}\n </Badge>\n ))}\n </div>\n )}\n {cta && !cta.implicit && (\n <FeaturedLink\n url=\"#\"\n additionalCSS={cn(\n \"pt-0 pointer-events-none font-medium items-center text-neutral-800 dark:text-neutral-500 group-hover/content-tile:text-neutral-1300 dark:group-hover/content-tile:text-neutral-000 transition-colors [&_svg]:group-hover/content-tile:left-0\",\n ctaClassName,\n )}\n iconColor=\"text-orange-600\"\n >\n {cta.text}\n </FeaturedLink>\n )}\n </div>\n </div>\n );\n};\n\nexport default ContentTile;\n"],"names":["useCallback","useMemo","Badge","FeaturedLink","Icon","cn","ContentTile","title","className","description","cta","feature","featureType","featureIcons","centerFeature","badges","onClick","featureClassName","titleClassName","descriptionClassName","ctaClassName","handleClick","url","window","location","href","renderedFeature","div","length","map","icon","idx","key","name","size","onKeyDown","e","preventDefault","tabIndex","role","h2","label","badgeProps","implicit","additionalCSS","iconColor","text"],"mappings":"AACA,OAASA,WAAW,CAAEC,OAAO,KAAQ,OAAQ,AAC7C,QAAOC,UAAgC,SAAU,AACjD,QAAOC,iBAAkB,gBAAiB,AAC1C,QAAOC,SAAU,QAAS,AAE1B,QAAOC,OAAQ,YAAa,CA0C5B,MAAMC,YAA0C,CAAC,CAC/CC,KAAK,CACLC,SAAS,CACTC,WAAW,CACXC,GAAG,CACHC,OAAO,CACPC,YAAc,OAAO,CACrBC,YAAY,CACZC,aAAa,CACbC,MAAM,CACNC,OAAO,CACPC,gBAAgB,CAChBC,cAAc,CACdC,oBAAoB,CACpBC,YAAY,CACb,IACC,MAAMC,YAAcrB,YAAY,KAC9B,GAAI,CAACU,IAAK,OAEV,GAAIM,QAAS,CACXA,QAAQN,IAAIY,GAAG,CACjB,KAAO,CACLC,OAAOC,QAAQ,CAACC,IAAI,CAAGf,IAAIY,GAAG,AAChC,CACF,EAAG,CAACN,QAASN,IAAI,EAEjB,MAAMgB,gBAAkBzB,QAAQ,KAC9B,GAAI,CAACU,QAAS,OAAO,KAErB,GAAIC,cAAgB,QAAS,CAC3B,OACE,oBAACe,OACCnB,UAAWH,GACT,qOACAS,eAAiB,oBACjBJ,KACE,+FACFO,mBAGF,oBAACU,OACCnB,UAAWH,GACT,oCACA,CAACS,eAAiB,6CAGnBH,SAEFE,cAAgBA,cAAce,OAAS,GACtC,oBAACD,OAAInB,UAAU,qJACZK,aAAagB,GAAG,CAAC,CAACC,KAAMC,MACvB,oBAAC3B,MAAK4B,IAAKF,KAAOC,IAAKE,KAAMH,KAAMI,KAAK,WAMpD,CAEA,GAAItB,cAAgB,OAAQ,CAC1B,OACE,oBAACe,OAAInB,UAAWH,GAAG,MAAOY,mBACvB,OAAON,UAAY,SAClB,oBAACP,MAAK6B,KAAMtB,QAAqBuB,KAAK,SAEtCvB,QAIR,CAEA,OAAO,IACT,EAAG,CACDG,cACAJ,IACAC,QACAM,iBACAJ,aACAD,YACD,EAED,OACE,oBAACe,OACCnB,UAAWH,GAAG,qBAAsBK,KAAO,iBAAkBF,WAC5D,GAAIE,KAAO,CACVM,QAASK,YACTc,UAAW,AAACC,IACV,GAAIA,EAAEJ,GAAG,GAAK,SAAWI,EAAEJ,GAAG,GAAK,IAAK,CACtCI,EAAEC,cAAc,GAChBhB,aACF,CACF,EACAiB,SAAU,EACVC,KAAM,OACN,aAAchC,KAChB,CAAC,EAEAmB,gBACD,oBAACC,OAAInB,UAAU,8BACZD,OACC,oBAACiC,MACChC,UAAWH,GACT,mFACAa,iBAGDX,OAGJE,aACC,oBAACkB,OACCnB,UAAWH,GACT,+LACAc,uBAGDV,aAGJM,QAAUA,OAAOa,MAAM,CAAG,GACzB,oBAACD,OAAInB,UAAU,kDACZO,OAAOc,GAAG,CAAC,CAAC,CAAEY,KAAK,CAAEjC,SAAS,CAAE,GAAGkC,WAAY,CAAEX,MAChD,oBAAC7B,OACC8B,IAAKS,MAAQV,IACbvB,UAAWH,GAAG,wBAAyBG,WACtC,GAAGkC,UAAU,EAEbD,SAKR/B,KAAO,CAACA,IAAIiC,QAAQ,EACnB,oBAACxC,cACCmB,IAAI,IACJsB,cAAevC,GACb,+OACAe,cAEFyB,UAAU,mBAETnC,IAAIoC,IAAI,GAMrB,CAEA,gBAAexC,WAAY"}
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"es-toolkit/compat";import{COLLAPSE_TRIGGER_DISTANCE}from"./Notice/component";const FLEXIBLE_DESKTOP_CLASSES="hidden md:flex flex-1 items-center h-full";const MAX_MOBILE_MENU_WIDTH="560px";const Header=({className,isNoticeBannerEnabled=false,noticeHeight=0,searchBar,searchButton,logoHref,headerLinks,headerLinksClassName,headerCenterClassName,nav,mobileNav,sessionState,themedScrollpoints=[],searchButtonVisibility="all",location,logoBadge})=>{const[showMenu,setShowMenu]=useState(false);const[fadingOut,setFadingOut]=useState(false);const[noticeBannerVisible,setNoticeBannerVisible]=useState(isNoticeBannerEnabled);const menuRef=useRef(null);const[scrollpointClasses,setScrollpointClasses]=useState(themedScrollpoints.length>0?themedScrollpoints[0].className:"");const headerProps=useMemo(()=>({style:{height:HEADER_HEIGHT,top:noticeBannerVisible?`${noticeHeight}px`:"0"},className:cn("fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-colors px-6 lg:px-16",scrollpointClasses,{"md:top-auto":noticeBannerVisible})}),[noticeBannerVisible,noticeHeight,scrollpointClasses]);const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};useEffect(()=>{const handleNoticeClose=()=>{setNoticeBannerVisible(false)};document.addEventListener("notice-closed",handleNoticeClose);return()=>document.removeEventListener("notice-closed",handleNoticeClose)},[]);useEffect(()=>{const handleScroll=()=>{const noticeElement=document.querySelector('[data-id="ui-notice"]');const isNoticeClosedToBeHidden=noticeElement?.classList.contains("ui-announcement-hidden");setNoticeBannerVisible(window.scrollY<=COLLAPSE_TRIGGER_DISTANCE&&isNoticeBannerEnabled&&!isNoticeClosedToBeHidden);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,100);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints,isNoticeBannerEnabled]);useEffect(()=>{const handleResize=()=>{if(window.innerWidth>=1040){setShowMenu(false)}};window.addEventListener("resize",handleResize);return()=>window.removeEventListener("resize",handleResize)},[]);useEffect(()=>{if(showMenu){document.body.classList.add("overflow-hidden")}else{document.body.classList.remove("overflow-hidden")}return()=>{document.body.classList.remove("overflow-hidden")}},[showMenu]);useEffect(()=>{if(location&&showMenu){closeMenu()}},[location,showMenu]);const wrappedSearchButton=useMemo(()=>searchButton?React.createElement("div",{className:"text-neutral-1300 dark:text-neutral-000 flex items-center"},searchButton):null,[searchButton]);return React.createElement(React.Fragment,null,React.createElement("header",{role:"banner",...headerProps},React.createElement("div",{className:cn("flex items-center h-full",className)},React.createElement("nav",{className:"flex flex-1 h-full items-center"},["light","dark"].map(theme=>React.createElement(Logo,{key:theme,href:logoHref,theme:theme,badge:logoBadge,additionalLinkAttrs:{className:cn("h-full focus-base rounded mr-4 lg:mr-8",{"flex dark:hidden":theme==="light","hidden dark:flex":theme==="dark"})}})),React.createElement("div",{className:FLEXIBLE_DESKTOP_CLASSES},nav)),React.createElement("div",{className:"flex md:hidden flex-1 items-center justify-end gap-6 h-full"},searchButtonVisibility!=="desktop"?wrappedSearchButton:null,React.createElement("button",{className:"cursor-pointer focus-base rounded flex items-center p-0",onClick:()=>setShowMenu(!showMenu),"aria-expanded":showMenu,"aria-controls":"mobile-menu","aria-label":"Toggle menu"},React.createElement(Icon,{name:showMenu?"icon-gui-x-mark-outline":"icon-gui-bars-3-outline",additionalCSS:"text-neutral-1300 dark:text-neutral-000",size:"1.5rem"}))),searchBar?React.createElement("div",{className:cn(FLEXIBLE_DESKTOP_CLASSES,"justify-center",headerCenterClassName)},searchBar):null,React.createElement(HeaderLinks,{className:cn(FLEXIBLE_DESKTOP_CLASSES,headerLinksClassName),headerLinks:headerLinks,sessionState:sessionState,searchButton:wrappedSearchButton,searchButtonVisibility:searchButtonVisibility}))),showMenu?React.createElement(React.Fragment,null,React.createElement("div",{className:cn("fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40",{"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]":!fadingOut,"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]":fadingOut}),onClick:closeMenu,onKeyDown:e=>e.key==="Escape"&&closeMenu(),role:"presentation"}),React.createElement("div",{id:"mobile-menu",className:"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50",style:{maxWidth:MAX_MOBILE_MENU_WIDTH,maxHeight:componentMaxHeight(HEADER_HEIGHT,HEADER_BOTTOM_MARGIN)},ref:menuRef,role:"navigation"},mobileNav,React.createElement(HeaderLinks,{headerLinks:headerLinks,sessionState:sessionState}))):null)};export default Header;
1
+ import React,{useState,useEffect,useRef,useMemo,useCallback}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"es-toolkit/compat";import{COLLAPSE_TRIGGER_DISTANCE}from"./Notice/component";const FLEXIBLE_DESKTOP_CLASSES="hidden md:flex flex-1 items-center h-full";const MAX_MOBILE_MENU_WIDTH="560px";const Header=({className,isNoticeBannerEnabled=false,noticeHeight=0,searchBar,searchButton,logoHref,headerLinks,headerLinksClassName,headerCenterClassName,nav,mobileNav,sessionState,themedScrollpoints=[],searchButtonVisibility="all",location,logoBadge})=>{const[showMenu,setShowMenu]=useState(false);const[fadingOut,setFadingOut]=useState(false);const[noticeBannerVisible,setNoticeBannerVisible]=useState(isNoticeBannerEnabled);const menuRef=useRef(null);const[scrollpointClasses,setScrollpointClasses]=useState(themedScrollpoints.length>0?themedScrollpoints[0].className:"");const headerStyle={height:HEADER_HEIGHT,top:noticeBannerVisible?`${noticeHeight}px`:"0"};const headerClassName=cn("fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-all duration-300 ease-in-out px-6 lg:px-16",scrollpointClasses,{"md:top-auto":noticeBannerVisible});const closeMenu=()=>{setFadingOut(true);setTimeout(()=>{setShowMenu(false);setFadingOut(false)},150)};const handleNoticeClose=useCallback(()=>{setNoticeBannerVisible(false)},[]);useEffect(()=>{document.addEventListener("notice-closed",handleNoticeClose);return()=>document.removeEventListener("notice-closed",handleNoticeClose)},[handleNoticeClose]);useEffect(()=>{const handleScroll=()=>{const noticeElement=document.querySelector('[data-id="ui-notice"]');const isNoticeClosedToBeHidden=noticeElement?.classList.contains("ui-announcement-hidden");setNoticeBannerVisible(window.scrollY<=COLLAPSE_TRIGGER_DISTANCE&&isNoticeBannerEnabled&&!isNoticeClosedToBeHidden);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,100);handleScroll();window.addEventListener("scroll",throttledHandleScroll);return()=>window.removeEventListener("scroll",throttledHandleScroll)},[themedScrollpoints,isNoticeBannerEnabled]);useEffect(()=>{const handleResize=()=>{if(window.innerWidth>=1040){setShowMenu(false)}};window.addEventListener("resize",handleResize);return()=>window.removeEventListener("resize",handleResize)},[]);useEffect(()=>{if(showMenu){document.body.classList.add("overflow-hidden")}else{document.body.classList.remove("overflow-hidden")}return()=>{document.body.classList.remove("overflow-hidden")}},[showMenu]);useEffect(()=>{if(location&&showMenu){closeMenu()}},[location,showMenu]);const wrappedSearchButton=useMemo(()=>searchButton?React.createElement("div",{className:"text-neutral-1300 dark:text-neutral-000 flex items-center"},searchButton):null,[searchButton]);return React.createElement(React.Fragment,null,React.createElement("header",{role:"banner",style:headerStyle,className:headerClassName},React.createElement("div",{className:cn("flex items-center h-full",className)},React.createElement("nav",{className:"flex flex-1 h-full items-center"},["light","dark"].map(theme=>React.createElement(Logo,{key:theme,href:logoHref,theme:theme,badge:logoBadge,additionalLinkAttrs:{className:cn("h-full focus-base rounded mr-4 lg:mr-8",{"flex dark:hidden":theme==="light","hidden dark:flex":theme==="dark"})}})),React.createElement("div",{className:FLEXIBLE_DESKTOP_CLASSES},nav)),React.createElement("div",{className:"flex md:hidden flex-1 items-center justify-end gap-6 h-full"},searchButtonVisibility!=="desktop"?wrappedSearchButton:null,React.createElement("button",{className:"cursor-pointer focus-base rounded flex items-center p-0",onClick:()=>setShowMenu(!showMenu),"aria-expanded":showMenu,"aria-controls":"mobile-menu","aria-label":"Toggle menu"},React.createElement(Icon,{name:showMenu?"icon-gui-x-mark-outline":"icon-gui-bars-3-outline",additionalCSS:"text-neutral-1300 dark:text-neutral-000",size:"1.5rem"}))),searchBar?React.createElement("div",{className:cn(FLEXIBLE_DESKTOP_CLASSES,"justify-center",headerCenterClassName)},searchBar):null,React.createElement(HeaderLinks,{className:cn(FLEXIBLE_DESKTOP_CLASSES,headerLinksClassName),headerLinks:headerLinks,sessionState:sessionState,searchButton:wrappedSearchButton,searchButtonVisibility:searchButtonVisibility}))),showMenu?React.createElement(React.Fragment,null,React.createElement("div",{className:cn("fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40",{"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]":!fadingOut,"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]":fadingOut}),onClick:closeMenu,onKeyDown:e=>e.key==="Escape"&&closeMenu(),role:"presentation"}),React.createElement("div",{id:"mobile-menu",className:"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50",style:{maxWidth:MAX_MOBILE_MENU_WIDTH,maxHeight:componentMaxHeight(HEADER_HEIGHT,HEADER_BOTTOM_MARGIN)},ref:menuRef,role:"navigation"},mobileNav,React.createElement(HeaderLinks,{headerLinks:headerLinks,sessionState:sessionState}))):null)};export default Header;
2
2
  //# sourceMappingURL=Header.js.map
@@ -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 \"es-toolkit/compat\";\nimport { Theme } from \"./styles/colors/types\";\nimport { COLLAPSE_TRIGGER_DISTANCE } from \"./Notice/component\";\n\nexport type ThemedScrollpoint = {\n id: string;\n className: string;\n};\n\n/**\n * Represents the state of the user session in the header.\n */\nexport type HeaderSessionState = {\n /**\n * Indicates if the user is signed in.\n */\n signedIn: boolean;\n\n /**\n * Information required to log out the user.\n */\n logOut: {\n /**\n * Token used for logging out.\n */\n token: string;\n\n /**\n * URL to log out the user.\n */\n href: string;\n };\n\n /**\n * Name of the user's account.\n */\n accountName: string;\n};\n\n/**\n * Props for the Header component.\n */\nexport type HeaderProps = {\n /**\n * Optional classnames to add to the header\n */\n className?: string;\n /**\n * Indicates if the notice banner is enabled.\n */\n isNoticeBannerEnabled?: boolean;\n /**\n * Height of the notice banner in pixels.\n */\n noticeHeight?: number;\n /**\n * Optional search bar element.\n */\n searchBar?: ReactNode;\n\n /**\n * Optional search button element.\n */\n searchButton?: ReactNode;\n\n /**\n * URL for the logo link.\n */\n logoHref?: string;\n\n /**\n * Array of header links.\n */\n headerLinks?: {\n /**\n * URL for the link.\n */\n href: string;\n\n /**\n * Label for the link.\n */\n label: string;\n\n /**\n * Indicates if the link should open in a new tab.\n */\n external?: boolean;\n }[];\n\n /**\n * Optional classname for styling the header links container.\n */\n headerLinksClassName?: string;\n\n /**\n * Optional classname for styling the header center container.\n */\n headerCenterClassName?: string;\n\n /**\n * Optional desktop navigation element.\n */\n nav?: ReactNode;\n\n /**\n * Optional mobile navigation element.\n */\n mobileNav?: ReactNode;\n\n /**\n * State of the user session.\n */\n sessionState?: HeaderSessionState;\n\n /**\n * Array of themed scrollpoints. The header will change its appearance based on the scrollpoint in view.\n */\n themedScrollpoints?: ThemedScrollpoint[];\n\n /**\n * Visibility setting for the search button.\n * - \"all\": Visible on all devices.\n * - \"desktop\": Visible only on desktop devices.\n * - \"mobile\": Visible only on mobile devices.\n */\n searchButtonVisibility?: \"all\" | \"desktop\" | \"mobile\";\n\n /**\n * Optional location object to detect location changes.\n */\n location?: Location;\n\n /**\n * Optional badge text to display on the logo.\n */\n logoBadge?: string;\n};\n\nconst FLEXIBLE_DESKTOP_CLASSES = \"hidden md:flex flex-1 items-center h-full\";\n\n/**\n * Maximum width before the menu expanded into full width\n */\nconst MAX_MOBILE_MENU_WIDTH = \"560px\";\n\nconst Header: React.FC<HeaderProps> = ({\n className,\n isNoticeBannerEnabled = false,\n noticeHeight = 0,\n searchBar,\n searchButton,\n logoHref,\n headerLinks,\n headerLinksClassName,\n headerCenterClassName,\n nav,\n mobileNav,\n sessionState,\n themedScrollpoints = [],\n searchButtonVisibility = \"all\",\n location,\n logoBadge,\n}) => {\n const [showMenu, setShowMenu] = useState(false);\n const [fadingOut, setFadingOut] = useState(false);\n const [noticeBannerVisible, setNoticeBannerVisible] = useState(\n isNoticeBannerEnabled,\n );\n const menuRef = useRef<HTMLDivElement>(null);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\n themedScrollpoints.length > 0 ? themedScrollpoints[0].className : \"\",\n );\n\n const headerProps = useMemo(\n () => ({\n style: {\n height: HEADER_HEIGHT,\n top: noticeBannerVisible ? `${noticeHeight}px` : \"0\",\n },\n className: cn(\n \"fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-colors px-6 lg:px-16\",\n scrollpointClasses,\n {\n \"md:top-auto\": noticeBannerVisible,\n },\n ),\n }),\n [noticeBannerVisible, noticeHeight, scrollpointClasses],\n );\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n useEffect(() => {\n const handleNoticeClose = () => {\n setNoticeBannerVisible(false);\n };\n\n document.addEventListener(\"notice-closed\", handleNoticeClose);\n return () =>\n document.removeEventListener(\"notice-closed\", handleNoticeClose);\n }, []);\n\n useEffect(() => {\n const handleScroll = () => {\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n const isNoticeClosedToBeHidden = noticeElement?.classList.contains(\n \"ui-announcement-hidden\",\n );\n setNoticeBannerVisible(\n window.scrollY <= COLLAPSE_TRIGGER_DISTANCE &&\n isNoticeBannerEnabled &&\n !isNoticeClosedToBeHidden,\n );\n for (const scrollpoint of themedScrollpoints) {\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT) {\n setScrollpointClasses(scrollpoint.className);\n return;\n }\n }\n }\n };\n\n const throttledHandleScroll = throttle(handleScroll, 100);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints, isNoticeBannerEnabled]);\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth >= 1040) {\n setShowMenu(false);\n }\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n if (showMenu) {\n document.body.classList.add(\"overflow-hidden\");\n } else {\n document.body.classList.remove(\"overflow-hidden\");\n }\n\n // Cleanup on unmount\n return () => {\n document.body.classList.remove(\"overflow-hidden\");\n };\n }, [showMenu]);\n\n // Close menu when location changes\n useEffect(() => {\n if (location && showMenu) {\n closeMenu();\n }\n }, [location, showMenu]);\n\n const wrappedSearchButton = useMemo(\n () =>\n searchButton ? (\n <div className=\"text-neutral-1300 dark:text-neutral-000 flex items-center\">\n {searchButton}\n </div>\n ) : null,\n [searchButton],\n );\n\n return (\n <>\n <header role=\"banner\" {...headerProps}>\n <div className={cn(\"flex items-center h-full\", className)}>\n <nav className=\"flex flex-1 h-full items-center\">\n {([\"light\", \"dark\"] as Theme[]).map((theme) => (\n <Logo\n key={theme}\n href={logoHref}\n theme={theme}\n badge={logoBadge}\n additionalLinkAttrs={{\n className: cn(\"h-full focus-base rounded mr-4 lg:mr-8\", {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n }),\n }}\n />\n ))}\n <div className={FLEXIBLE_DESKTOP_CLASSES}>{nav}</div>\n </nav>\n <div className=\"flex md:hidden flex-1 items-center justify-end gap-6 h-full\">\n {searchButtonVisibility !== \"desktop\" ? wrappedSearchButton : null}\n <button\n className=\"cursor-pointer focus-base rounded flex items-center p-0\"\n onClick={() => setShowMenu(!showMenu)}\n aria-expanded={showMenu}\n aria-controls=\"mobile-menu\"\n aria-label=\"Toggle menu\"\n >\n <Icon\n name={\n showMenu\n ? \"icon-gui-x-mark-outline\"\n : \"icon-gui-bars-3-outline\"\n }\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n size=\"1.5rem\"\n />\n </button>\n </div>\n {searchBar ? (\n <div\n className={cn(\n FLEXIBLE_DESKTOP_CLASSES,\n \"justify-center\",\n headerCenterClassName,\n )}\n >\n {searchBar}\n </div>\n ) : null}\n <HeaderLinks\n className={cn(FLEXIBLE_DESKTOP_CLASSES, headerLinksClassName)}\n headerLinks={headerLinks}\n sessionState={sessionState}\n searchButton={wrappedSearchButton}\n searchButtonVisibility={searchButtonVisibility}\n />\n </div>\n </header>\n {showMenu ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40\",\n {\n \"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]\":\n !fadingOut,\n \"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]\":\n fadingOut,\n },\n )}\n onClick={closeMenu}\n onKeyDown={(e) => e.key === \"Escape\" && closeMenu()}\n role=\"presentation\"\n />\n <div\n id=\"mobile-menu\"\n className=\"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50\"\n style={{\n maxWidth: MAX_MOBILE_MENU_WIDTH,\n maxHeight: componentMaxHeight(\n HEADER_HEIGHT,\n HEADER_BOTTOM_MARGIN,\n ),\n }}\n ref={menuRef}\n role=\"navigation\"\n >\n {mobileNav}\n <HeaderLinks\n headerLinks={headerLinks}\n sessionState={sessionState}\n />\n </div>\n </>\n ) : null}\n </>\n );\n};\n\nexport default Header;\n"],"names":["React","useState","useEffect","useRef","useMemo","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","COLLAPSE_TRIGGER_DISTANCE","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","className","isNoticeBannerEnabled","noticeHeight","searchBar","searchButton","logoHref","headerLinks","headerLinksClassName","headerCenterClassName","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","location","logoBadge","showMenu","setShowMenu","fadingOut","setFadingOut","noticeBannerVisible","setNoticeBannerVisible","menuRef","scrollpointClasses","setScrollpointClasses","length","headerProps","style","height","top","closeMenu","setTimeout","handleNoticeClose","document","addEventListener","removeEventListener","handleScroll","noticeElement","querySelector","isNoticeClosedToBeHidden","classList","contains","window","scrollY","scrollpoint","element","getElementById","id","rect","getBoundingClientRect","bottom","throttledHandleScroll","handleResize","innerWidth","body","add","remove","wrappedSearchButton","div","header","role","map","theme","key","href","badge","additionalLinkAttrs","button","onClick","aria-expanded","aria-controls","aria-label","name","additionalCSS","size","onKeyDown","e","maxWidth","maxHeight","ref"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/Header.tsx"],"sourcesContent":["import React, {\n useState,\n useEffect,\n useRef,\n ReactNode,\n useMemo,\n useCallback,\n} 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 \"es-toolkit/compat\";\nimport { Theme } from \"./styles/colors/types\";\nimport { COLLAPSE_TRIGGER_DISTANCE } from \"./Notice/component\";\n\nexport type ThemedScrollpoint = {\n id: string;\n className: string;\n};\n\n/**\n * Represents the state of the user session in the header.\n */\nexport type HeaderSessionState = {\n /**\n * Indicates if the user is signed in.\n */\n signedIn: boolean;\n\n /**\n * Information required to log out the user.\n */\n logOut: {\n /**\n * Token used for logging out.\n */\n token: string;\n\n /**\n * URL to log out the user.\n */\n href: string;\n };\n\n /**\n * Name of the user's account.\n */\n accountName: string;\n};\n\n/**\n * Props for the Header component.\n */\nexport type HeaderProps = {\n /**\n * Optional classnames to add to the header\n */\n className?: string;\n /**\n * Indicates if the notice banner is enabled.\n */\n isNoticeBannerEnabled?: boolean;\n /**\n * Height of the notice banner in pixels.\n */\n noticeHeight?: number;\n /**\n * Optional search bar element.\n */\n searchBar?: ReactNode;\n\n /**\n * Optional search button element.\n */\n searchButton?: ReactNode;\n\n /**\n * URL for the logo link.\n */\n logoHref?: string;\n\n /**\n * Array of header links.\n */\n headerLinks?: {\n /**\n * URL for the link.\n */\n href: string;\n\n /**\n * Label for the link.\n */\n label: string;\n\n /**\n * Indicates if the link should open in a new tab.\n */\n external?: boolean;\n }[];\n\n /**\n * Optional classname for styling the header links container.\n */\n headerLinksClassName?: string;\n\n /**\n * Optional classname for styling the header center container.\n */\n headerCenterClassName?: string;\n\n /**\n * Optional desktop navigation element.\n */\n nav?: ReactNode;\n\n /**\n * Optional mobile navigation element.\n */\n mobileNav?: ReactNode;\n\n /**\n * State of the user session.\n */\n sessionState?: HeaderSessionState;\n\n /**\n * Array of themed scrollpoints. The header will change its appearance based on the scrollpoint in view.\n */\n themedScrollpoints?: ThemedScrollpoint[];\n\n /**\n * Visibility setting for the search button.\n * - \"all\": Visible on all devices.\n * - \"desktop\": Visible only on desktop devices.\n * - \"mobile\": Visible only on mobile devices.\n */\n searchButtonVisibility?: \"all\" | \"desktop\" | \"mobile\";\n\n /**\n * Optional location object to detect location changes.\n */\n location?: Location;\n\n /**\n * Optional badge text to display on the logo.\n */\n logoBadge?: string;\n};\n\nconst FLEXIBLE_DESKTOP_CLASSES = \"hidden md:flex flex-1 items-center h-full\";\n\n/**\n * Maximum width before the menu expanded into full width\n */\nconst MAX_MOBILE_MENU_WIDTH = \"560px\";\n\nconst Header: React.FC<HeaderProps> = ({\n className,\n isNoticeBannerEnabled = false,\n noticeHeight = 0,\n searchBar,\n searchButton,\n logoHref,\n headerLinks,\n headerLinksClassName,\n headerCenterClassName,\n nav,\n mobileNav,\n sessionState,\n themedScrollpoints = [],\n searchButtonVisibility = \"all\",\n location,\n logoBadge,\n}) => {\n const [showMenu, setShowMenu] = useState(false);\n const [fadingOut, setFadingOut] = useState(false);\n const [noticeBannerVisible, setNoticeBannerVisible] = useState(\n isNoticeBannerEnabled,\n );\n const menuRef = useRef<HTMLDivElement>(null);\n const [scrollpointClasses, setScrollpointClasses] = useState<string>(\n themedScrollpoints.length > 0 ? themedScrollpoints[0].className : \"\",\n );\n\n const headerStyle = {\n height: HEADER_HEIGHT,\n top: noticeBannerVisible ? `${noticeHeight}px` : \"0\",\n };\n\n const headerClassName = cn(\n \"fixed left-0 top-0 w-full z-50 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300 dark:border-neutral-1000 transition-all duration-300 ease-in-out px-6 lg:px-16\",\n scrollpointClasses,\n {\n \"md:top-auto\": noticeBannerVisible,\n },\n );\n\n const closeMenu = () => {\n setFadingOut(true);\n\n setTimeout(() => {\n setShowMenu(false);\n setFadingOut(false);\n }, 150);\n };\n\n const handleNoticeClose = useCallback(() => {\n setNoticeBannerVisible(false);\n }, []);\n\n useEffect(() => {\n document.addEventListener(\"notice-closed\", handleNoticeClose);\n return () =>\n document.removeEventListener(\"notice-closed\", handleNoticeClose);\n }, [handleNoticeClose]);\n\n useEffect(() => {\n const handleScroll = () => {\n const noticeElement = document.querySelector('[data-id=\"ui-notice\"]');\n const isNoticeClosedToBeHidden = noticeElement?.classList.contains(\n \"ui-announcement-hidden\",\n );\n setNoticeBannerVisible(\n window.scrollY <= COLLAPSE_TRIGGER_DISTANCE &&\n isNoticeBannerEnabled &&\n !isNoticeClosedToBeHidden,\n );\n for (const scrollpoint of themedScrollpoints) {\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT) {\n setScrollpointClasses(scrollpoint.className);\n return;\n }\n }\n }\n };\n\n const throttledHandleScroll = throttle(handleScroll, 100);\n\n handleScroll();\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n return () => window.removeEventListener(\"scroll\", throttledHandleScroll);\n }, [themedScrollpoints, isNoticeBannerEnabled]);\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth >= 1040) {\n setShowMenu(false);\n }\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n if (showMenu) {\n document.body.classList.add(\"overflow-hidden\");\n } else {\n document.body.classList.remove(\"overflow-hidden\");\n }\n\n // Cleanup on unmount\n return () => {\n document.body.classList.remove(\"overflow-hidden\");\n };\n }, [showMenu]);\n\n // Close menu when location changes\n useEffect(() => {\n if (location && showMenu) {\n closeMenu();\n }\n }, [location, showMenu]);\n\n const wrappedSearchButton = useMemo(\n () =>\n searchButton ? (\n <div className=\"text-neutral-1300 dark:text-neutral-000 flex items-center\">\n {searchButton}\n </div>\n ) : null,\n [searchButton],\n );\n\n return (\n <>\n <header role=\"banner\" style={headerStyle} className={headerClassName}>\n <div className={cn(\"flex items-center h-full\", className)}>\n <nav className=\"flex flex-1 h-full items-center\">\n {([\"light\", \"dark\"] as Theme[]).map((theme) => (\n <Logo\n key={theme}\n href={logoHref}\n theme={theme}\n badge={logoBadge}\n additionalLinkAttrs={{\n className: cn(\"h-full focus-base rounded mr-4 lg:mr-8\", {\n \"flex dark:hidden\": theme === \"light\",\n \"hidden dark:flex\": theme === \"dark\",\n }),\n }}\n />\n ))}\n <div className={FLEXIBLE_DESKTOP_CLASSES}>{nav}</div>\n </nav>\n <div className=\"flex md:hidden flex-1 items-center justify-end gap-6 h-full\">\n {searchButtonVisibility !== \"desktop\" ? wrappedSearchButton : null}\n <button\n className=\"cursor-pointer focus-base rounded flex items-center p-0\"\n onClick={() => setShowMenu(!showMenu)}\n aria-expanded={showMenu}\n aria-controls=\"mobile-menu\"\n aria-label=\"Toggle menu\"\n >\n <Icon\n name={\n showMenu\n ? \"icon-gui-x-mark-outline\"\n : \"icon-gui-bars-3-outline\"\n }\n additionalCSS=\"text-neutral-1300 dark:text-neutral-000\"\n size=\"1.5rem\"\n />\n </button>\n </div>\n {searchBar ? (\n <div\n className={cn(\n FLEXIBLE_DESKTOP_CLASSES,\n \"justify-center\",\n headerCenterClassName,\n )}\n >\n {searchBar}\n </div>\n ) : null}\n <HeaderLinks\n className={cn(FLEXIBLE_DESKTOP_CLASSES, headerLinksClassName)}\n headerLinks={headerLinks}\n sessionState={sessionState}\n searchButton={wrappedSearchButton}\n searchButtonVisibility={searchButtonVisibility}\n />\n </div>\n </header>\n {showMenu ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 z-40\",\n {\n \"animate-[fade-in-ten-percent_150ms_ease-in-out_forwards]\":\n !fadingOut,\n \"animate-[fade-out-ten-percent_150ms_ease-in-out_forwards]\":\n fadingOut,\n },\n )}\n onClick={closeMenu}\n onKeyDown={(e) => e.key === \"Escape\" && closeMenu()}\n role=\"presentation\"\n />\n <div\n id=\"mobile-menu\"\n className=\"md:hidden fixed flex flex-col top-[4.75rem] overflow-y-hidden mx-3 right-0 w-[calc(100%-24px)] bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-50\"\n style={{\n maxWidth: MAX_MOBILE_MENU_WIDTH,\n maxHeight: componentMaxHeight(\n HEADER_HEIGHT,\n HEADER_BOTTOM_MARGIN,\n ),\n }}\n ref={menuRef}\n role=\"navigation\"\n >\n {mobileNav}\n <HeaderLinks\n headerLinks={headerLinks}\n sessionState={sessionState}\n />\n </div>\n </>\n ) : null}\n </>\n );\n};\n\nexport default Header;\n"],"names":["React","useState","useEffect","useRef","useMemo","useCallback","Icon","cn","Logo","componentMaxHeight","HEADER_BOTTOM_MARGIN","HEADER_HEIGHT","HeaderLinks","throttle","COLLAPSE_TRIGGER_DISTANCE","FLEXIBLE_DESKTOP_CLASSES","MAX_MOBILE_MENU_WIDTH","Header","className","isNoticeBannerEnabled","noticeHeight","searchBar","searchButton","logoHref","headerLinks","headerLinksClassName","headerCenterClassName","nav","mobileNav","sessionState","themedScrollpoints","searchButtonVisibility","location","logoBadge","showMenu","setShowMenu","fadingOut","setFadingOut","noticeBannerVisible","setNoticeBannerVisible","menuRef","scrollpointClasses","setScrollpointClasses","length","headerStyle","height","top","headerClassName","closeMenu","setTimeout","handleNoticeClose","document","addEventListener","removeEventListener","handleScroll","noticeElement","querySelector","isNoticeClosedToBeHidden","classList","contains","window","scrollY","scrollpoint","element","getElementById","id","rect","getBoundingClientRect","bottom","throttledHandleScroll","handleResize","innerWidth","body","add","remove","wrappedSearchButton","div","header","role","style","map","theme","key","href","badge","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 CHANGED
@@ -1,2 +1,2 @@
1
- import React,{useEffect,useMemo}from"react";import Header from"./Header";import Flyout from"./Flyout";import{menuItemsForHeader}from"./Meganav/data";import{MeganavMobile}from"./Meganav/MeganavMobile";import Notice from"./Notice";import{HEADER_HEIGHT}from"./utils/heights";const Meganav=({sessionState,notice,theme,themedScrollpoints,onNoticeClose})=>{const[noticeHeight,setNoticeHeight]=React.useState(0);const memoizedNoticeHeight=useMemo(()=>{if(!notice){return 0}return noticeHeight},[notice,noticeHeight]);const mobileNavItems=useMemo(()=>menuItemsForHeader.filter(item=>!item.isHiddenMobile).map(({name,link,content})=>({name,link,content})),[]);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){setNoticeHeight(0);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 inset-0 w-full z-50",id:theme==="dark"?"meganav-theme-dark":"meganav","data-testid":"meganav",style:{height:HEADER_HEIGHT+memoizedNoticeHeight}},notice&&React.createElement(Notice,{...notice.props,config:notice.config,onClose:onNoticeClose}),React.createElement(Header,{className:"max-w-screen-xl mx-auto px-0 sm:px-8 md:px-10 lg:px-16",isNoticeBannerEnabled:!!notice,noticeHeight:memoizedNoticeHeight,nav:React.createElement(Flyout,{menuItems:menuItemsForHeader,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{menuItemsForHeader}from"./Meganav/data";import{MeganavMobile}from"./Meganav/MeganavMobile";import Notice from"./Notice";import{HEADER_HEIGHT}from"./utils/heights";const Meganav=({sessionState,notice,theme,themedScrollpoints,onNoticeClose})=>{const[noticeHeight,setNoticeHeight]=React.useState(0);const finalNoticeHeight=notice?noticeHeight:0;const mobileNavItems=useMemo(()=>menuItemsForHeader.filter(item=>!item.isHiddenMobile).map(({name,link,content})=>({name,link,content})),[]);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){setNoticeHeight(0);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 inset-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 px-0 sm:px-8 md:px-10 lg:px-16",isNoticeBannerEnabled:!!notice,noticeHeight:finalNoticeHeight,nav:React.createElement(Flyout,{menuItems:menuItemsForHeader,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 { menuItemsForHeader } from \"./Meganav/data\";\nimport { MeganavMobile } from \"./Meganav/MeganavMobile\";\nimport Notice from \"./Notice\";\nimport { HEADER_HEIGHT } from \"./utils/heights\";\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 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}: MeganavProps) => {\n const [noticeHeight, setNoticeHeight] = React.useState(0);\n\n const memoizedNoticeHeight = useMemo(() => {\n if (!notice) {\n return 0;\n }\n return noticeHeight;\n }, [notice, noticeHeight]);\n\n const mobileNavItems = useMemo(\n () =>\n menuItemsForHeader\n .filter((item) => !item.isHiddenMobile)\n .map(({ name, link, content }) => ({ name, link, content })),\n [],\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) {\n setNoticeHeight(0);\n return;\n }\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 inset-0 w-full z-50\"\n id={theme === \"dark\" ? \"meganav-theme-dark\" : \"meganav\"}\n data-testid=\"meganav\"\n style={{ height: HEADER_HEIGHT + memoizedNoticeHeight }}\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 px-0 sm:px-8 md:px-10 lg:px-16\"\n isNoticeBannerEnabled={!!notice}\n noticeHeight={memoizedNoticeHeight}\n nav={\n <Flyout\n menuItems={menuItemsForHeader}\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","menuItemsForHeader","MeganavMobile","Notice","HEADER_HEIGHT","Meganav","sessionState","notice","theme","themedScrollpoints","onNoticeClose","noticeHeight","setNoticeHeight","useState","memoizedNoticeHeight","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,kBAAkB,KAAQ,gBAAiB,AACpD,QAASC,aAAa,KAAQ,yBAA0B,AACxD,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,iBAAkB,CA2BhD,MAAMC,QAAU,CAAC,CACfC,YAAY,CACZC,MAAM,CACNC,KAAK,CACLC,kBAAkB,CAClBC,aAAa,CACA,IACb,KAAM,CAACC,aAAcC,gBAAgB,CAAGhB,MAAMiB,QAAQ,CAAC,GAEvD,MAAMC,qBAAuBhB,QAAQ,KACnC,GAAI,CAACS,OAAQ,CACX,OAAO,CACT,CACA,OAAOI,YACT,EAAG,CAACJ,OAAQI,aAAa,EAEzB,MAAMI,eAAiBjB,QACrB,IACEG,mBACGe,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,EAAE,EAGJ,MAAMC,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,CAED5B,UAAU,KACR,GAAI,CAACU,OAAQ,CACXK,gBAAgB,GAChB,MACF,CAEA,MAAMc,cAAgBC,SAASC,aAAa,CAAC,yBAC7C,GAAI,CAACF,cAAe,OAEpB,MAAMG,mBAAqB,KACzBjB,gBAAgBc,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,CAACtB,OAAO,EAEX,OACE,wCACE,oBAACmC,OACCjB,UAAU,+BACVD,GAAIhB,QAAU,OAAS,qBAAuB,UAC9CmC,cAAY,UACZC,MAAO,CAAEb,OAAQ3B,cAAgBU,oBAAqB,GAErDP,QACC,oBAACJ,QACE,GAAGI,OAAOsC,KAAK,CAChBC,OAAQvC,OAAOuC,MAAM,CACrBC,QAASrC,gBAGb,oBAACX,QACC0B,UAAU,yDACVuB,sBAAuB,CAAC,CAACzC,OACzBI,aAAcG,qBACdmC,IACE,oBAACjD,QACCkD,UAAWjD,mBACXwB,UAAU,oBACV0B,gBAAgB,oBAChBC,kBAAkB,iIAGtBC,UAAW,oBAACnD,eAAcoD,SAAUvC,iBACpCwC,YAAa,CAAC,CAAEC,KAAM,WAAYC,MAAO,YAAa,EAAE,CACxDC,qBAAqB,cACrBpD,aAAcA,aACdG,mBAAoBA,oBAAsBc,6BAKpD,CAEA,gBAAelB,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 { menuItemsForHeader } from \"./Meganav/data\";\nimport { MeganavMobile } from \"./Meganav/MeganavMobile\";\nimport Notice from \"./Notice\";\nimport { HEADER_HEIGHT } from \"./utils/heights\";\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 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}: MeganavProps) => {\n const [noticeHeight, setNoticeHeight] = React.useState(0);\n\n const finalNoticeHeight = notice ? noticeHeight : 0;\n\n const mobileNavItems = useMemo(\n () =>\n menuItemsForHeader\n .filter((item) => !item.isHiddenMobile)\n .map(({ name, link, content }) => ({ name, link, content })),\n [],\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) {\n setNoticeHeight(0);\n return;\n }\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 inset-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 px-0 sm:px-8 md:px-10 lg:px-16\"\n isNoticeBannerEnabled={!!notice}\n noticeHeight={finalNoticeHeight}\n nav={\n <Flyout\n menuItems={menuItemsForHeader}\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","menuItemsForHeader","MeganavMobile","Notice","HEADER_HEIGHT","Meganav","sessionState","notice","theme","themedScrollpoints","onNoticeClose","noticeHeight","setNoticeHeight","useState","finalNoticeHeight","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,kBAAkB,KAAQ,gBAAiB,AACpD,QAASC,aAAa,KAAQ,yBAA0B,AACxD,QAAOC,WAAY,UAAW,AAC9B,QAASC,aAAa,KAAQ,iBAAkB,CA2BhD,MAAMC,QAAU,CAAC,CACfC,YAAY,CACZC,MAAM,CACNC,KAAK,CACLC,kBAAkB,CAClBC,aAAa,CACA,IACb,KAAM,CAACC,aAAcC,gBAAgB,CAAGhB,MAAMiB,QAAQ,CAAC,GAEvD,MAAMC,kBAAoBP,OAASI,aAAe,EAElD,MAAMI,eAAiBjB,QACrB,IACEG,mBACGe,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,EAAE,EAGJ,MAAMC,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,CAED5B,UAAU,KACR,GAAI,CAACU,OAAQ,CACXK,gBAAgB,GAChB,MACF,CAEA,MAAMc,cAAgBC,SAASC,aAAa,CAAC,yBAC7C,GAAI,CAACF,cAAe,OAEpB,MAAMG,mBAAqB,KACzBjB,gBAAgBc,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,CAACtB,OAAO,EAEX,OACE,wCACE,oBAACmC,OACCjB,UAAU,+BACVD,GAAIhB,QAAU,OAAS,qBAAuB,UAC9CmC,cAAY,UACZC,MAAO,CAAEb,OAAQ3B,cAAgBU,iBAAkB,GAElDP,QACC,oBAACJ,QACE,GAAGI,OAAOsC,KAAK,CAChBC,OAAQvC,OAAOuC,MAAM,CACrBC,QAASrC,gBAGb,oBAACX,QACC0B,UAAU,yDACVuB,sBAAuB,CAAC,CAACzC,OACzBI,aAAcG,kBACdmC,IACE,oBAACjD,QACCkD,UAAWjD,mBACXwB,UAAU,oBACV0B,gBAAgB,oBAChBC,kBAAkB,iIAGtBC,UAAW,oBAACnD,eAAcoD,SAAUvC,iBACpCwC,YAAa,CAAC,CAAEC,KAAM,WAAYC,MAAO,YAAa,EAAE,CACxDC,qBAAqB,cACrBpD,aAAcA,aACdG,mBAAoBA,oBAAsBc,6BAKpD,CAEA,gBAAelB,OAAQ"}
@@ -1,6 +1,6 @@
1
1
  @layer components {
2
2
  .ui-announcement {
3
- @apply font-sans transition-[max-height,transform,opacity] duration-150 ease-in-out;
3
+ @apply font-sans transition-[max-height,transform,opacity] duration-300 ease-in-out;
4
4
  }
5
5
 
6
6
  .ui-announcement-visible {
package/core/Notice.js CHANGED
@@ -1,2 +1,2 @@
1
- import React,{useEffect,useRef,useState}from"react";import DOMPurify from"dompurify";import Icon from"./Icon";import cn from"./utils/cn.js";import NoticeScripts from"./Notice/component.js";import useRailsUjsLinks from"./hooks/use-rails-ujs-hooks";const defaultTextColor="text-neutral-1300 dark:text-neutral-000";const contentWrapperClasses="w-full pr-2 ui-text-p4 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-orange-100 dark:bg-orange-1100",textColor=defaultTextColor,onClose})=>{const contentRef=useRef(null);const[isClosing,setIsClosing]=useState(false);useRailsUjsLinks(contentRef);useEffect(()=>{const cleanup=NoticeScripts({bannerContainer:document.querySelector('[data-id="ui-notice"]'),cookieId:config?.cookieId,noticeId:config?.noticeId,options:{collapse:config?.options?.collapse||false}});return cleanup},[config?.cookieId,config?.noticeId,config?.options?.collapse]);const safeContent=DOMPurify.sanitize(bodyText??"",{ALLOWED_TAGS:["a"],ALLOWED_ATTR:["href","data-method"],ALLOWED_URI_REGEXP:/^\/[^/]/});return React.createElement("div",{className:cn("ui-announcement relative z-[60]",isClosing?"ui-announcement-hidden":"ui-announcement-visible",bgColor,textColor),"data-id":"ui-notice"},React.createElement("div",{className:"ui-grid-px py-4 max-w-screen-xl mx-auto flex items-start"},React.createElement(ContentWrapper,{buttonLink:buttonLink??"#"},React.createElement("strong",{className:"font-bold whitespace-nowrap pr-1"},title),React.createElement("span",{ref:contentRef,className:"pr-1",dangerouslySetInnerHTML:{__html:safeContent}}),buttonLabel&&React.createElement("span",{className:"cursor-pointer whitespace-nowrap text-gui-blue-default-light dark:text-gui-blue-default-dark"},buttonLabel)),closeBtn&&React.createElement("button",{type:"button",className:"ml-auto h-5 w-5 border-none bg-none self-baseline",onClick:()=>{setIsClosing(true);setTimeout(()=>{document.dispatchEvent(new CustomEvent("notice-closed"));onClose?.()},100)}},React.createElement(Icon,{name:"icon-gui-x-mark-outline",size:"1.25rem",color:textColor}))))};export default Notice;
1
+ import React,{useEffect,useRef,useState}from"react";import DOMPurify from"dompurify";import Icon from"./Icon";import cn from"./utils/cn.js";import NoticeScripts from"./Notice/component.js";import useRailsUjsLinks from"./hooks/use-rails-ujs-hooks";const defaultTextColor="text-neutral-1300 dark:text-neutral-000";const contentWrapperClasses="w-full pr-2 ui-text-p4 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-orange-100 dark:bg-orange-1100",textColor=defaultTextColor,onClose})=>{const contentRef=useRef(null);const[isClosing,setIsClosing]=useState(false);useRailsUjsLinks(contentRef);useEffect(()=>{const cleanup=NoticeScripts({bannerContainer:document.querySelector('[data-id="ui-notice"]'),cookieId:config?.cookieId,noticeId:config?.noticeId,options:{collapse:config?.options?.collapse||false}});return cleanup},[config?.cookieId,config?.noticeId,config?.options?.collapse]);const safeContent=DOMPurify.sanitize(bodyText??"",{ALLOWED_TAGS:["a"],ALLOWED_ATTR:["href","data-method"],ALLOWED_URI_REGEXP:/^\/[^/]/});return React.createElement("div",{className:cn("ui-announcement relative z-[60]",isClosing?"ui-announcement-hidden max-h-0 -translate-y-full opacity-0 overflow-hidden":"ui-announcement-visible",bgColor,textColor),"data-id":"ui-notice"},React.createElement("div",{className:"ui-grid-px py-4 max-w-screen-xl mx-auto flex items-start"},React.createElement(ContentWrapper,{buttonLink:buttonLink??"#"},React.createElement("strong",{className:"font-bold whitespace-nowrap pr-1"},title),React.createElement("span",{ref:contentRef,className:"pr-1",dangerouslySetInnerHTML:{__html:safeContent}}),buttonLabel&&React.createElement("span",{className:"cursor-pointer whitespace-nowrap text-gui-blue-default-light dark:text-gui-blue-default-dark"},buttonLabel)),closeBtn&&React.createElement("button",{type:"button",className:"ml-auto h-5 w-5 border-none bg-none self-baseline outline-none focus:outline-none focus:ring-0 focus:border-transparent",onClick:()=>{setIsClosing(true);setTimeout(()=>{document.dispatchEvent(new CustomEvent("notice-closed"));onClose?.()},300)}},React.createElement(Icon,{name:"icon-gui-x-mark-outline",size:"1.25rem",color:textColor}))))};export default Notice;
2
2
  //# sourceMappingURL=Notice.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/Notice.tsx"],"sourcesContent":["import React, { ReactNode, useEffect, useRef, useState } from \"react\";\nimport DOMPurify from \"dompurify\";\n\nimport { ColorClass, ColorThemeSet } from \"./styles/colors/types\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn.js\";\nimport NoticeScripts from \"./Notice/component.js\";\nimport useRailsUjsLinks from \"./hooks/use-rails-ujs-hooks\";\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 onClose?: () => void;\n\n bannerContainer?: Element | null;\n cookieId?: string;\n noticeId?: string;\n options?: { collapse: boolean };\n};\n\nconst defaultTextColor = \"text-neutral-1300 dark:text-neutral-000\";\n\nconst contentWrapperClasses = \"w-full pr-2 ui-text-p4 self-center\";\n\nconst ContentWrapper = ({\n buttonLink,\n textColor = defaultTextColor,\n children,\n}: 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-orange-100 dark:bg-orange-1100\",\n textColor = defaultTextColor,\n onClose,\n}: NoticeProps) => {\n const contentRef = useRef<HTMLSpanElement>(null);\n const [isClosing, setIsClosing] = useState(false);\n useRailsUjsLinks(contentRef);\n\n useEffect(() => {\n const cleanup = 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 return cleanup;\n }, [config?.cookieId, config?.noticeId, config?.options?.collapse]);\n\n const safeContent = DOMPurify.sanitize(bodyText ?? \"\", {\n ALLOWED_TAGS: [\"a\"],\n ALLOWED_ATTR: [\"href\", \"data-method\"],\n ALLOWED_URI_REGEXP: /^\\/[^/]/,\n });\n\n return (\n <div\n className={cn(\n \"ui-announcement relative z-[60]\",\n isClosing ? \"ui-announcement-hidden\" : \"ui-announcement-visible\",\n bgColor,\n textColor,\n )}\n data-id=\"ui-notice\"\n >\n <div className=\"ui-grid-px py-4 max-w-screen-xl mx-auto flex items-start\">\n <ContentWrapper buttonLink={buttonLink ?? \"#\"}>\n <strong className=\"font-bold whitespace-nowrap pr-1\">{title}</strong>\n <span\n ref={contentRef}\n className=\"pr-1\"\n dangerouslySetInnerHTML={{\n __html: safeContent,\n }}\n ></span>\n {buttonLabel && (\n <span className=\"cursor-pointer whitespace-nowrap text-gui-blue-default-light dark:text-gui-blue-default-dark\">\n {buttonLabel}\n </span>\n )}\n </ContentWrapper>\n\n {closeBtn && (\n <button\n type=\"button\"\n className=\"ml-auto h-5 w-5 border-none bg-none self-baseline\"\n onClick={() => {\n setIsClosing(true);\n setTimeout(() => {\n document.dispatchEvent(new CustomEvent(\"notice-closed\"));\n onClose?.();\n }, 100);\n }}\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","useRef","useState","DOMPurify","Icon","cn","NoticeScripts","useRailsUjsLinks","defaultTextColor","contentWrapperClasses","ContentWrapper","buttonLink","textColor","children","a","href","className","div","Notice","buttonLabel","bodyText","title","config","closeBtn","bgColor","onClose","contentRef","isClosing","setIsClosing","cleanup","bannerContainer","document","querySelector","cookieId","noticeId","options","collapse","safeContent","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","ALLOWED_URI_REGEXP","data-id","strong","span","ref","dangerouslySetInnerHTML","__html","button","type","onClick","setTimeout","dispatchEvent","CustomEvent","name","size","color"],"mappings":"AAAA,OAAOA,OAAoBC,SAAS,CAAEC,MAAM,CAAEC,QAAQ,KAAQ,OAAQ,AACtE,QAAOC,cAAe,WAAY,AAGlC,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,eAAgB,AAC/B,QAAOC,kBAAmB,uBAAwB,AAClD,QAAOC,qBAAsB,6BAA8B,CAmC3D,MAAMC,iBAAmB,0CAEzB,MAAMC,sBAAwB,qCAE9B,MAAMC,eAAiB,CAAC,CACtBC,UAAU,CACVC,UAAYJ,gBAAgB,CAC5BK,QAAQ,CACY,GACpBF,WACE,oBAACG,KAAEC,KAAMJ,WAAYK,UAAWX,GAAGI,sBAAuBG,YACvDC,UAGH,oBAACI,OAAID,UAAWX,GAAGI,sBAAuBG,YAAaC,UAG3D,MAAMK,OAAS,CAAC,CACdP,UAAU,CACVQ,WAAW,CACXC,QAAQ,CACRC,KAAK,CACLC,MAAM,CACNC,QAAQ,CACRC,QAAU,mCAAmC,CAC7CZ,UAAYJ,gBAAgB,CAC5BiB,OAAO,CACK,IACZ,MAAMC,WAAazB,OAAwB,MAC3C,KAAM,CAAC0B,UAAWC,aAAa,CAAG1B,SAAS,OAC3CK,iBAAiBmB,YAEjB1B,UAAU,KACR,MAAM6B,QAAUvB,cAAc,CAC5BwB,gBAAiBC,SAASC,aAAa,CAAC,yBACxCC,SAAUX,QAAQW,SAClBC,SAAUZ,QAAQY,SAClBC,QAAS,CACPC,SAAUd,QAAQa,SAASC,UAAY,KACzC,CACF,GAEA,OAAOP,OACT,EAAG,CAACP,QAAQW,SAAUX,QAAQY,SAAUZ,QAAQa,SAASC,SAAS,EAElE,MAAMC,YAAclC,UAAUmC,QAAQ,CAAClB,UAAY,GAAI,CACrDmB,aAAc,CAAC,IAAI,CACnBC,aAAc,CAAC,OAAQ,cAAc,CACrCC,mBAAoB,SACtB,GAEA,OACE,oBAACxB,OACCD,UAAWX,GACT,kCACAsB,UAAY,yBAA2B,0BACvCH,QACAZ,WAEF8B,UAAQ,aAER,oBAACzB,OAAID,UAAU,4DACb,oBAACN,gBAAeC,WAAYA,YAAc,KACxC,oBAACgC,UAAO3B,UAAU,oCAAoCK,OACtD,oBAACuB,QACCC,IAAKnB,WACLV,UAAU,OACV8B,wBAAyB,CACvBC,OAAQV,WACV,IAEDlB,aACC,oBAACyB,QAAK5B,UAAU,gGACbG,cAKNI,UACC,oBAACyB,UACCC,KAAK,SACLjC,UAAU,oDACVkC,QAAS,KACPtB,aAAa,MACbuB,WAAW,KACTpB,SAASqB,aAAa,CAAC,IAAIC,YAAY,kBACvC5B,WACF,EAAG,IACL,GAEA,oBAACrB,MACCkD,KAAK,0BACLC,KAAK,UACLC,MAAO5C,cAOrB,CAEA,gBAAeM,MAAO"}
1
+ {"version":3,"sources":["../../src/core/Notice.tsx"],"sourcesContent":["import React, { ReactNode, useEffect, useRef, useState } from \"react\";\nimport DOMPurify from \"dompurify\";\n\nimport { ColorClass, ColorThemeSet } from \"./styles/colors/types\";\nimport Icon from \"./Icon\";\nimport cn from \"./utils/cn.js\";\nimport NoticeScripts from \"./Notice/component.js\";\nimport useRailsUjsLinks from \"./hooks/use-rails-ujs-hooks\";\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 onClose?: () => void;\n\n bannerContainer?: Element | null;\n cookieId?: string;\n noticeId?: string;\n options?: { collapse: boolean };\n};\n\nconst defaultTextColor = \"text-neutral-1300 dark:text-neutral-000\";\n\nconst contentWrapperClasses = \"w-full pr-2 ui-text-p4 self-center\";\n\nconst ContentWrapper = ({\n buttonLink,\n textColor = defaultTextColor,\n children,\n}: 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-orange-100 dark:bg-orange-1100\",\n textColor = defaultTextColor,\n onClose,\n}: NoticeProps) => {\n const contentRef = useRef<HTMLSpanElement>(null);\n const [isClosing, setIsClosing] = useState(false);\n useRailsUjsLinks(contentRef);\n\n useEffect(() => {\n const cleanup = 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 return cleanup;\n }, [config?.cookieId, config?.noticeId, config?.options?.collapse]);\n\n const safeContent = DOMPurify.sanitize(bodyText ?? \"\", {\n ALLOWED_TAGS: [\"a\"],\n ALLOWED_ATTR: [\"href\", \"data-method\"],\n ALLOWED_URI_REGEXP: /^\\/[^/]/,\n });\n\n // have to add the style classes here as src/core/Notice/component.css is not being properly imported or distributed when ably-ui is used as a package.\n return (\n <div\n className={cn(\n \"ui-announcement relative z-[60]\",\n isClosing\n ? \"ui-announcement-hidden max-h-0 -translate-y-full opacity-0 overflow-hidden\"\n : \"ui-announcement-visible\",\n bgColor,\n textColor,\n )}\n data-id=\"ui-notice\"\n >\n <div className=\"ui-grid-px py-4 max-w-screen-xl mx-auto flex items-start\">\n <ContentWrapper buttonLink={buttonLink ?? \"#\"}>\n <strong className=\"font-bold whitespace-nowrap pr-1\">{title}</strong>\n <span\n ref={contentRef}\n className=\"pr-1\"\n dangerouslySetInnerHTML={{\n __html: safeContent,\n }}\n ></span>\n {buttonLabel && (\n <span className=\"cursor-pointer whitespace-nowrap text-gui-blue-default-light dark:text-gui-blue-default-dark\">\n {buttonLabel}\n </span>\n )}\n </ContentWrapper>\n\n {closeBtn && (\n <button\n type=\"button\"\n className=\"ml-auto h-5 w-5 border-none bg-none self-baseline outline-none focus:outline-none focus:ring-0 focus:border-transparent\"\n onClick={() => {\n setIsClosing(true);\n setTimeout(() => {\n document.dispatchEvent(new CustomEvent(\"notice-closed\"));\n onClose?.();\n }, 300);\n }}\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","useRef","useState","DOMPurify","Icon","cn","NoticeScripts","useRailsUjsLinks","defaultTextColor","contentWrapperClasses","ContentWrapper","buttonLink","textColor","children","a","href","className","div","Notice","buttonLabel","bodyText","title","config","closeBtn","bgColor","onClose","contentRef","isClosing","setIsClosing","cleanup","bannerContainer","document","querySelector","cookieId","noticeId","options","collapse","safeContent","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","ALLOWED_URI_REGEXP","data-id","strong","span","ref","dangerouslySetInnerHTML","__html","button","type","onClick","setTimeout","dispatchEvent","CustomEvent","name","size","color"],"mappings":"AAAA,OAAOA,OAAoBC,SAAS,CAAEC,MAAM,CAAEC,QAAQ,KAAQ,OAAQ,AACtE,QAAOC,cAAe,WAAY,AAGlC,QAAOC,SAAU,QAAS,AAC1B,QAAOC,OAAQ,eAAgB,AAC/B,QAAOC,kBAAmB,uBAAwB,AAClD,QAAOC,qBAAsB,6BAA8B,CAmC3D,MAAMC,iBAAmB,0CAEzB,MAAMC,sBAAwB,qCAE9B,MAAMC,eAAiB,CAAC,CACtBC,UAAU,CACVC,UAAYJ,gBAAgB,CAC5BK,QAAQ,CACY,GACpBF,WACE,oBAACG,KAAEC,KAAMJ,WAAYK,UAAWX,GAAGI,sBAAuBG,YACvDC,UAGH,oBAACI,OAAID,UAAWX,GAAGI,sBAAuBG,YAAaC,UAG3D,MAAMK,OAAS,CAAC,CACdP,UAAU,CACVQ,WAAW,CACXC,QAAQ,CACRC,KAAK,CACLC,MAAM,CACNC,QAAQ,CACRC,QAAU,mCAAmC,CAC7CZ,UAAYJ,gBAAgB,CAC5BiB,OAAO,CACK,IACZ,MAAMC,WAAazB,OAAwB,MAC3C,KAAM,CAAC0B,UAAWC,aAAa,CAAG1B,SAAS,OAC3CK,iBAAiBmB,YAEjB1B,UAAU,KACR,MAAM6B,QAAUvB,cAAc,CAC5BwB,gBAAiBC,SAASC,aAAa,CAAC,yBACxCC,SAAUX,QAAQW,SAClBC,SAAUZ,QAAQY,SAClBC,QAAS,CACPC,SAAUd,QAAQa,SAASC,UAAY,KACzC,CACF,GAEA,OAAOP,OACT,EAAG,CAACP,QAAQW,SAAUX,QAAQY,SAAUZ,QAAQa,SAASC,SAAS,EAElE,MAAMC,YAAclC,UAAUmC,QAAQ,CAAClB,UAAY,GAAI,CACrDmB,aAAc,CAAC,IAAI,CACnBC,aAAc,CAAC,OAAQ,cAAc,CACrCC,mBAAoB,SACtB,GAGA,OACE,oBAACxB,OACCD,UAAWX,GACT,kCACAsB,UACI,6EACA,0BACJH,QACAZ,WAEF8B,UAAQ,aAER,oBAACzB,OAAID,UAAU,4DACb,oBAACN,gBAAeC,WAAYA,YAAc,KACxC,oBAACgC,UAAO3B,UAAU,oCAAoCK,OACtD,oBAACuB,QACCC,IAAKnB,WACLV,UAAU,OACV8B,wBAAyB,CACvBC,OAAQV,WACV,IAEDlB,aACC,oBAACyB,QAAK5B,UAAU,gGACbG,cAKNI,UACC,oBAACyB,UACCC,KAAK,SACLjC,UAAU,0HACVkC,QAAS,KACPtB,aAAa,MACbuB,WAAW,KACTpB,SAASqB,aAAa,CAAC,IAAIC,YAAY,kBACvC5B,WACF,EAAG,IACL,GAEA,oBAACrB,MACCkD,KAAK,0BACLC,KAAK,UACLC,MAAO5C,cAOrB,CAEA,gBAAeM,MAAO"}
package/index.d.ts CHANGED
@@ -196,7 +196,7 @@ import { ColorClassColorGroups } from "@ably/ui/core/styles/colors/types";
196
196
  /**
197
197
  * Props for the Badge component.
198
198
  */
199
- interface BadgeProps {
199
+ export interface BadgeProps {
200
200
  /**
201
201
  * The size of the badge. Can be one of "xs", "sm", "md", or "lg".
202
202
  */
@@ -479,6 +479,56 @@ export default ConnectStateWrapper;
479
479
  //# sourceMappingURL=ConnectStateWrapper.d.ts.map
480
480
  }
481
481
 
482
+ declare module '@ably/ui/core/ContentTile' {
483
+ import type React from "react";
484
+ import { type BadgeProps } from "@ably/ui/core/Badge";
485
+ import type { IconName } from "@ably/ui/core/Icon/types";
486
+ type ContentTileProps = {
487
+ /** The title text to display */
488
+ title?: string;
489
+ /** Additional CSS classes for the root container */
490
+ className?: string;
491
+ /** The description text to display */
492
+ description?: string;
493
+ /**
494
+ * Call-to-action configuration.
495
+ * - text: The CTA button or link text.
496
+ * - url: The destination URL for the CTA.
497
+ * - implicit: If true, no explicit CTA button is shown.
498
+ */
499
+ cta?: {
500
+ text: string;
501
+ url: string;
502
+ implicit?: boolean;
503
+ };
504
+ /** Content to display in the feature area (image or icon) */
505
+ feature?: React.ReactNode | string;
506
+ /** Type of feature to render - either 'image' or 'icon' */
507
+ featureType?: "image" | "icon";
508
+ /** Array of icon names to display as overlays on the feature */
509
+ featureIcons?: IconName[];
510
+ /** Whether to vertically center the feature content */
511
+ centerFeature?: boolean;
512
+ /** Array of badges to display */
513
+ badges?: (BadgeProps & {
514
+ label: string;
515
+ })[];
516
+ /** Custom click handler, receives the CTA URL if present */
517
+ onClick?: (url?: string) => void;
518
+ /** Additional CSS classes for the feature element */
519
+ featureClassName?: string;
520
+ /** Additional CSS classes for the title element */
521
+ titleClassName?: string;
522
+ /** Additional CSS classes for the description element */
523
+ descriptionClassName?: string;
524
+ /** Additional CSS classes for the CTA element */
525
+ ctaClassName?: string;
526
+ };
527
+ const ContentTile: React.FC<ContentTileProps>;
528
+ export default ContentTile;
529
+ //# sourceMappingURL=ContentTile.d.ts.map
530
+ }
531
+
482
532
  declare module '@ably/ui/core/CookieMessage' {
483
533
  type CookieMessageProps = {
484
534
  cookieId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ably/ui",
3
- "version": "17.8.0-dev.becb7c12",
3
+ "version": "17.8.0",
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",
@@ -44,7 +44,7 @@
44
44
  "eslint-config-prettier": "^10.1.8",
45
45
  "eslint-plugin-jsx-a11y": "^6.10.2",
46
46
  "eslint-plugin-react": "^7.35.0",
47
- "eslint-plugin-react-hooks": "^5.2.0",
47
+ "eslint-plugin-react-hooks": "^6.1.0",
48
48
  "eslint-plugin-react-perf": "^3.3.3",
49
49
  "eslint-plugin-storybook": "^9.1.4",
50
50
  "heroicons": "^2.2.0",