@otl-core/next-navigation 1.1.35 → 1.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { getBreakpointValue } from "@otl-core/cms-utils";
4
3
  import { useEffect, useMemo, useRef, useState } from "react";
5
4
  import { CSSTransition } from "react-transition-group";
6
5
  import { useNavigation } from "../../context/navigation-context";
@@ -140,16 +139,7 @@ function NavigationDropdown({
140
139
  zIndex: getDropdownZIndex(
141
140
  useSameLayerMode,
142
141
  navigation.style?.dropdown?.layer
143
- ),
144
- marginTop: navigation.style?.dropdown?.offset?.y ? getBreakpointValue(navigation.style.dropdown.offset.y, "base") : "0",
145
- marginLeft: navigation.style?.dropdown?.offset?.left ? getBreakpointValue(
146
- navigation.style.dropdown.offset.left,
147
- "base"
148
- ) : "0",
149
- marginRight: navigation.style?.dropdown?.offset?.right ? getBreakpointValue(
150
- navigation.style.dropdown.offset.right,
151
- "base"
152
- ) : "0"
142
+ )
153
143
  },
154
144
  children: /* @__PURE__ */ jsx(
155
145
  "div",
@@ -228,7 +218,7 @@ function NavigationDropdown({
228
218
  return /* @__PURE__ */ jsx(
229
219
  "nav",
230
220
  {
231
- className: `flex flex-col p-2 dropdown-content-${dropdownId}`,
221
+ className: `flex flex-col ${useSameLayerMode ? "" : "p-2"} dropdown-content-${dropdownId}`,
232
222
  style: {
233
223
  ...linkHoverStyle,
234
224
  width: "100%",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/navigation/dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n Site,\n HeaderConfig,\n HeaderDropdownGroupConfig,\n HeaderNavigationItemConfig,\n HeaderNavigationItemDropdownConfig,\n} from \"@otl-core/cms-types\";\nimport { HeaderDropdownContent } from \"@otl-core/cms-types\";\nimport { getBreakpointValue } from \"@otl-core/cms-utils\";\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { useNavigation } from \"../../context/navigation-context\";\nimport { resolveBorderToCSS, resolveColorsToCSS } from \"@otl-core/style-utils\";\nimport { DropdownContentItem } from \"../items/dropdown-content-item\";\n\nfunction getDropdownTimeout(isMobileMenu: boolean): number {\n return isMobileMenu ? 300 : 200;\n}\n\nfunction getDropdownClassNames(isMobileMenu: boolean): string {\n return isMobileMenu ? \"mobile-menu\" : \"desktop-dropdown\";\n}\n\nfunction getDropdownZIndex(\n isSameLayer: boolean,\n layer?: string,\n): number | undefined {\n if (isSameLayer) return undefined;\n return layer === \"above\" ? 9999 : undefined;\n}\n\ninterface NavigationDropdownProps {\n itemId: string;\n config: HeaderNavigationItemConfig;\n navigation: HeaderConfig;\n resolvedColors: Record<string, string | undefined>;\n styles: React.CSSProperties;\n linkStyle: React.CSSProperties;\n dropdownId: string;\n site: Site;\n containerContent?: boolean;\n isSameLayer?: boolean;\n}\nexport function NavigationDropdown({\n itemId,\n config,\n navigation,\n resolvedColors,\n dropdownId,\n site,\n containerContent = false,\n isSameLayer = false,\n}: NavigationDropdownProps) {\n const { activeDropdown } = useNavigation();\n const [navigationStack, setNavigationStack] = useState<string[]>([]);\n const nodeRef = useRef(null);\n const backButtonRef = useRef<HTMLButtonElement>(null);\n\n const isMobileMenu = useMemo(\n () => itemId.startsWith(\"mobile-menu\"),\n [itemId],\n );\n const isOpen = useMemo(\n () => activeDropdown === itemId,\n [activeDropdown, itemId],\n );\n const content: HeaderDropdownContent[] = useMemo(\n () => (config as HeaderNavigationItemDropdownConfig).content || [],\n [config],\n );\n\n // Reset nested content when dropdown closes (derived during render, no effect needed)\n const prevIsOpen = useRef(isOpen);\n if (prevIsOpen.current && !isOpen) {\n setNavigationStack([]);\n }\n prevIsOpen.current = isOpen;\n\n // Focus back button when navigating to nested content (DOM side effect, needs useEffect)\n useEffect(() => {\n if (navigationStack.length > 0 && backButtonRef.current) {\n backButtonRef.current.focus();\n }\n }, [navigationStack.length]);\n\n const handleNavigate = (contentId: string) => {\n setNavigationStack((prev) => [...prev, contentId]);\n };\n\n const handleBack = () => {\n setNavigationStack((prev) => prev.slice(0, -1));\n };\n\n // Helper to recursively find a dropdown by ID in content (including inside sections)\n const findDropdownById = (\n contentArray: HeaderDropdownContent[],\n id: string,\n ): HeaderDropdownContent | undefined => {\n for (const item of contentArray) {\n if (item.id === id && item.type === \"dropdown\") {\n return item;\n }\n // Search inside sections\n if (item.type === \"section\") {\n const config = item.config as HeaderDropdownGroupConfig;\n const found = findDropdownById(config.content, id);\n if (found) return found;\n }\n }\n return undefined;\n };\n\n // Build the navigation panels based on the stack\n const buildNavigationPanels = () => {\n const panels: Array<{\n content: HeaderDropdownContent[];\n depth: number;\n }> = [];\n\n // Root panel\n panels.push({ content: content, depth: 0 });\n\n // Build nested panels\n let currentContent = content;\n for (let i = 0; i < navigationStack.length; i++) {\n const contentId = navigationStack[i];\n const dropdownItem = findDropdownById(currentContent, contentId);\n\n if (dropdownItem && dropdownItem.config) {\n const nestedContent = (\n dropdownItem.config as HeaderNavigationItemDropdownConfig\n ).content;\n panels.push({ content: nestedContent, depth: i + 1 });\n currentContent = nestedContent;\n } else {\n break;\n }\n }\n\n return panels;\n };\n\n const panels = buildNavigationPanels();\n\n // Use the same color resolution as the rest of the system\n const dropdownColors = resolveColorsToCSS({\n dropdownMenuBackground: navigation.style?.dropdown?.background,\n dropdownMenuLinkColor: navigation.style?.dropdown?.link?.color,\n dropdownMenuLinkHoverColor: navigation.style?.dropdown?.link?.hoverColor,\n dropdownMenuLinkHoverBackground:\n navigation.style?.dropdown?.link?.hoverBackground,\n dropdownMenuTextColor: navigation.style?.dropdown?.textColor,\n });\n\n const dropdownMenuBackground = dropdownColors.dropdownMenuBackground;\n const dropdownMenuLinkColor = dropdownColors.dropdownMenuLinkColor;\n const dropdownMenuLinkHoverColor = dropdownColors.dropdownMenuLinkHoverColor;\n const dropdownMenuLinkHoverBackground =\n dropdownColors.dropdownMenuLinkHoverBackground || \"transparent\";\n const dropdownMenuTextColor = dropdownColors.dropdownMenuTextColor;\n\n const dropdownMenuBorder = useMemo(() => {\n if (!navigation.style?.dropdown?.border) return undefined;\n return resolveBorderToCSS(navigation.style.dropdown.border);\n }, [navigation.style?.dropdown?.border]);\n\n // Shadow is now handled via responsive CSS generation (generateResponsiveSpacingCSS)\n\n // Early return AFTER all hooks\n if (content.length === 0) return null;\n\n // Enhanced resolved colors for dropdown, using dropdown-specific text color if available\n const dropdownResolvedColors = {\n ...resolvedColors,\n text: dropdownMenuTextColor || resolvedColors.text,\n dropdownMenuLinkColor,\n };\n\n const useSameLayerMode = isSameLayer && !isMobileMenu;\n\n const dropdownStyles: React.CSSProperties = {\n backgroundColor: useSameLayerMode ? undefined : dropdownMenuBackground,\n color: dropdownMenuTextColor || dropdownMenuLinkColor,\n ...(useSameLayerMode ? {} : dropdownMenuBorder),\n };\n\n const linkHoverStyle = {\n \"--dropdown-link-hover-color\": dropdownMenuLinkHoverColor,\n \"--dropdown-link-hover-background\": dropdownMenuLinkHoverBackground,\n } as React.CSSProperties;\n\n return (\n <>\n <CSSTransition\n in={isOpen}\n nodeRef={nodeRef}\n timeout={useSameLayerMode ? 250 : getDropdownTimeout(isMobileMenu)}\n classNames={\n useSameLayerMode\n ? \"same-layer-dropdown\"\n : getDropdownClassNames(isMobileMenu)\n }\n unmountOnExit={!useSameLayerMode}\n >\n <div\n ref={nodeRef}\n className={`relative w-full navigation-dropdown-${dropdownId}`}\n style={{\n ...dropdownStyles,\n ...(useSameLayerMode\n ? { display: \"grid\", overflow: \"hidden\" }\n : { overflow: \"hidden\" }),\n zIndex: getDropdownZIndex(\n useSameLayerMode,\n navigation.style?.dropdown?.layer,\n ),\n marginTop: navigation.style?.dropdown?.offset?.y\n ? getBreakpointValue(navigation.style.dropdown.offset.y, \"base\")\n : \"0\",\n marginLeft: navigation.style?.dropdown?.offset?.left\n ? getBreakpointValue(\n navigation.style.dropdown.offset.left,\n \"base\",\n )\n : \"0\",\n marginRight: navigation.style?.dropdown?.offset?.right\n ? getBreakpointValue(\n navigation.style.dropdown.offset.right,\n \"base\",\n )\n : \"0\",\n }}\n >\n <div\n style={\n useSameLayerMode\n ? { overflow: \"hidden\", minHeight: 0 }\n : undefined\n }\n >\n <div\n style={{\n display: \"flex\",\n width: \"100%\",\n transform: `translateX(-${navigationStack.length * 100}%)`,\n transition: \"transform 300ms ease-in-out\",\n }}\n >\n {panels.map((panel, panelIndex) => {\n const isActive = panelIndex === navigationStack.length;\n const isToRight = panelIndex > navigationStack.length;\n\n const panelContent = (\n <>\n {panel.depth > 0 && (\n <button\n ref={\n panelIndex === navigationStack.length\n ? backButtonRef\n : null\n }\n onClick={(e) => {\n e.preventDefault();\n handleBack();\n }}\n type=\"button\"\n data-navigation-internal=\"true\"\n className=\"flex items-center px-3 py-2 text-sm rounded-md transition-colors mb-2\"\n style={{\n color:\n resolvedColors.dropdownMenuLinkColor ||\n resolvedColors.linkColor,\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className=\"mr-2\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n Back\n </button>\n )}\n\n <div className=\"flex flex-wrap gap-4\">\n {panel.content?.map((item: HeaderDropdownContent) => {\n if (item.type === \"section\") {\n return (\n <div key={item.id} className=\"flex-1 min-w-[200px]\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n }\n return (\n <div key={item.id} className=\"w-full\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n })}\n </div>\n </>\n );\n\n return (\n <nav\n key={panelIndex}\n className={`flex flex-col p-2 dropdown-content-${dropdownId}`}\n style={{\n ...linkHoverStyle,\n width: \"100%\",\n flexShrink: 0,\n transform: isToRight\n ? \"translateX(30px)\"\n : \"translateX(0)\",\n opacity: isActive ? 1 : 0.95,\n transition:\n \"transform 300ms ease-in-out, opacity 300ms ease-in-out\",\n }}\n inert={!isActive ? true : undefined}\n >\n {containerContent ? (\n <div className=\"container mx-auto\">{panelContent}</div>\n ) : (\n panelContent\n )}\n </nav>\n );\n })}\n </div>\n </div>\n </div>\n </CSSTransition>\n </>\n );\n}\n"],"mappings":"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","names":["config","panels"]}
1
+ {"version":3,"sources":["../../../src/components/navigation/dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n Site,\n HeaderConfig,\n HeaderDropdownGroupConfig,\n HeaderNavigationItemConfig,\n HeaderNavigationItemDropdownConfig,\n} from \"@otl-core/cms-types\";\nimport { HeaderDropdownContent } from \"@otl-core/cms-types\";\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { useNavigation } from \"../../context/navigation-context\";\nimport { resolveBorderToCSS, resolveColorsToCSS } from \"@otl-core/style-utils\";\nimport { DropdownContentItem } from \"../items/dropdown-content-item\";\n\nfunction getDropdownTimeout(isMobileMenu: boolean): number {\n return isMobileMenu ? 300 : 200;\n}\n\nfunction getDropdownClassNames(isMobileMenu: boolean): string {\n return isMobileMenu ? \"mobile-menu\" : \"desktop-dropdown\";\n}\n\nfunction getDropdownZIndex(\n isSameLayer: boolean,\n layer?: string,\n): number | undefined {\n if (isSameLayer) return undefined;\n return layer === \"above\" ? 9999 : undefined;\n}\n\ninterface NavigationDropdownProps {\n itemId: string;\n config: HeaderNavigationItemConfig;\n navigation: HeaderConfig;\n resolvedColors: Record<string, string | undefined>;\n styles: React.CSSProperties;\n linkStyle: React.CSSProperties;\n dropdownId: string;\n site: Site;\n containerContent?: boolean;\n isSameLayer?: boolean;\n}\nexport function NavigationDropdown({\n itemId,\n config,\n navigation,\n resolvedColors,\n dropdownId,\n site,\n containerContent = false,\n isSameLayer = false,\n}: NavigationDropdownProps) {\n const { activeDropdown } = useNavigation();\n const [navigationStack, setNavigationStack] = useState<string[]>([]);\n const nodeRef = useRef(null);\n const backButtonRef = useRef<HTMLButtonElement>(null);\n\n const isMobileMenu = useMemo(\n () => itemId.startsWith(\"mobile-menu\"),\n [itemId],\n );\n const isOpen = useMemo(\n () => activeDropdown === itemId,\n [activeDropdown, itemId],\n );\n const content: HeaderDropdownContent[] = useMemo(\n () => (config as HeaderNavigationItemDropdownConfig).content || [],\n [config],\n );\n\n // Reset nested content when dropdown closes (derived during render, no effect needed)\n const prevIsOpen = useRef(isOpen);\n if (prevIsOpen.current && !isOpen) {\n setNavigationStack([]);\n }\n prevIsOpen.current = isOpen;\n\n // Focus back button when navigating to nested content (DOM side effect, needs useEffect)\n useEffect(() => {\n if (navigationStack.length > 0 && backButtonRef.current) {\n backButtonRef.current.focus();\n }\n }, [navigationStack.length]);\n\n const handleNavigate = (contentId: string) => {\n setNavigationStack((prev) => [...prev, contentId]);\n };\n\n const handleBack = () => {\n setNavigationStack((prev) => prev.slice(0, -1));\n };\n\n // Helper to recursively find a dropdown by ID in content (including inside sections)\n const findDropdownById = (\n contentArray: HeaderDropdownContent[],\n id: string,\n ): HeaderDropdownContent | undefined => {\n for (const item of contentArray) {\n if (item.id === id && item.type === \"dropdown\") {\n return item;\n }\n // Search inside sections\n if (item.type === \"section\") {\n const config = item.config as HeaderDropdownGroupConfig;\n const found = findDropdownById(config.content, id);\n if (found) return found;\n }\n }\n return undefined;\n };\n\n // Build the navigation panels based on the stack\n const buildNavigationPanels = () => {\n const panels: Array<{\n content: HeaderDropdownContent[];\n depth: number;\n }> = [];\n\n // Root panel\n panels.push({ content: content, depth: 0 });\n\n // Build nested panels\n let currentContent = content;\n for (let i = 0; i < navigationStack.length; i++) {\n const contentId = navigationStack[i];\n const dropdownItem = findDropdownById(currentContent, contentId);\n\n if (dropdownItem && dropdownItem.config) {\n const nestedContent = (\n dropdownItem.config as HeaderNavigationItemDropdownConfig\n ).content;\n panels.push({ content: nestedContent, depth: i + 1 });\n currentContent = nestedContent;\n } else {\n break;\n }\n }\n\n return panels;\n };\n\n const panels = buildNavigationPanels();\n\n // Use the same color resolution as the rest of the system\n const dropdownColors = resolveColorsToCSS({\n dropdownMenuBackground: navigation.style?.dropdown?.background,\n dropdownMenuLinkColor: navigation.style?.dropdown?.link?.color,\n dropdownMenuLinkHoverColor: navigation.style?.dropdown?.link?.hoverColor,\n dropdownMenuLinkHoverBackground:\n navigation.style?.dropdown?.link?.hoverBackground,\n dropdownMenuTextColor: navigation.style?.dropdown?.textColor,\n });\n\n const dropdownMenuBackground = dropdownColors.dropdownMenuBackground;\n const dropdownMenuLinkColor = dropdownColors.dropdownMenuLinkColor;\n const dropdownMenuLinkHoverColor = dropdownColors.dropdownMenuLinkHoverColor;\n const dropdownMenuLinkHoverBackground =\n dropdownColors.dropdownMenuLinkHoverBackground || \"transparent\";\n const dropdownMenuTextColor = dropdownColors.dropdownMenuTextColor;\n\n const dropdownMenuBorder = useMemo(() => {\n if (!navigation.style?.dropdown?.border) return undefined;\n return resolveBorderToCSS(navigation.style.dropdown.border);\n }, [navigation.style?.dropdown?.border]);\n\n // Shadow is now handled via responsive CSS generation (generateResponsiveSpacingCSS)\n\n // Early return AFTER all hooks\n if (content.length === 0) return null;\n\n // Enhanced resolved colors for dropdown, using dropdown-specific text color if available\n const dropdownResolvedColors = {\n ...resolvedColors,\n text: dropdownMenuTextColor || resolvedColors.text,\n dropdownMenuLinkColor,\n };\n\n const useSameLayerMode = isSameLayer && !isMobileMenu;\n\n const dropdownStyles: React.CSSProperties = {\n backgroundColor: useSameLayerMode ? undefined : dropdownMenuBackground,\n color: dropdownMenuTextColor || dropdownMenuLinkColor,\n ...(useSameLayerMode ? {} : dropdownMenuBorder),\n };\n\n const linkHoverStyle = {\n \"--dropdown-link-hover-color\": dropdownMenuLinkHoverColor,\n \"--dropdown-link-hover-background\": dropdownMenuLinkHoverBackground,\n } as React.CSSProperties;\n\n return (\n <>\n <CSSTransition\n in={isOpen}\n nodeRef={nodeRef}\n timeout={useSameLayerMode ? 250 : getDropdownTimeout(isMobileMenu)}\n classNames={\n useSameLayerMode\n ? \"same-layer-dropdown\"\n : getDropdownClassNames(isMobileMenu)\n }\n unmountOnExit={!useSameLayerMode}\n >\n <div\n ref={nodeRef}\n className={`relative w-full navigation-dropdown-${dropdownId}`}\n style={{\n ...dropdownStyles,\n ...(useSameLayerMode\n ? { display: \"grid\", overflow: \"hidden\" }\n : { overflow: \"hidden\" }),\n zIndex: getDropdownZIndex(\n useSameLayerMode,\n navigation.style?.dropdown?.layer,\n ),\n }}\n >\n <div\n style={\n useSameLayerMode\n ? { overflow: \"hidden\", minHeight: 0 }\n : undefined\n }\n >\n <div\n style={{\n display: \"flex\",\n width: \"100%\",\n transform: `translateX(-${navigationStack.length * 100}%)`,\n transition: \"transform 300ms ease-in-out\",\n }}\n >\n {panels.map((panel, panelIndex) => {\n const isActive = panelIndex === navigationStack.length;\n const isToRight = panelIndex > navigationStack.length;\n\n const panelContent = (\n <>\n {panel.depth > 0 && (\n <button\n ref={\n panelIndex === navigationStack.length\n ? backButtonRef\n : null\n }\n onClick={(e) => {\n e.preventDefault();\n handleBack();\n }}\n type=\"button\"\n data-navigation-internal=\"true\"\n className=\"flex items-center px-3 py-2 text-sm rounded-md transition-colors mb-2\"\n style={{\n color:\n resolvedColors.dropdownMenuLinkColor ||\n resolvedColors.linkColor,\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className=\"mr-2\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n Back\n </button>\n )}\n\n <div className=\"flex flex-wrap gap-4\">\n {panel.content?.map((item: HeaderDropdownContent) => {\n if (item.type === \"section\") {\n return (\n <div key={item.id} className=\"flex-1 min-w-[200px]\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n }\n return (\n <div key={item.id} className=\"w-full\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n })}\n </div>\n </>\n );\n\n return (\n <nav\n key={panelIndex}\n className={`flex flex-col ${useSameLayerMode ? \"\" : \"p-2\"} dropdown-content-${dropdownId}`}\n style={{\n ...linkHoverStyle,\n width: \"100%\",\n flexShrink: 0,\n transform: isToRight\n ? \"translateX(30px)\"\n : \"translateX(0)\",\n opacity: isActive ? 1 : 0.95,\n transition:\n \"transform 300ms ease-in-out, opacity 300ms ease-in-out\",\n }}\n inert={!isActive ? true : undefined}\n >\n {containerContent ? (\n <div className=\"container mx-auto\">{panelContent}</div>\n ) : (\n panelContent\n )}\n </nav>\n );\n })}\n </div>\n </div>\n </div>\n </CSSTransition>\n </>\n );\n}\n"],"mappings":"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","names":["config","panels"]}
@@ -40,8 +40,7 @@ const Header = ({
40
40
  }) => {
41
41
  const isFixed = navigation.style?.position === "fixed";
42
42
  const containerBehavior = navigation.style?.container || "edged";
43
- const safeZone = navigation.style?.safeZone;
44
- const safeZoneHeight = typeof safeZone === "object" && "base" in safeZone ? safeZone.base : safeZone || "0";
43
+ const hasSafeZone = !!navigation.style?.safeZone;
45
44
  const estimatedWidth = calculateNavigationWidth(
46
45
  navigation.sections || [],
47
46
  site
@@ -89,7 +88,6 @@ const Header = ({
89
88
  const linkStyle = {
90
89
  ...resolvedColors.linkColor && { color: resolvedColors.linkColor }
91
90
  };
92
- const marginValue = typeof navigation.style?.layout?.margin === "object" && "base" in navigation.style.layout.margin ? navigation.style.layout.margin.base : navigation.style?.layout?.margin || "0";
93
91
  const sortedSections = [...navigation.sections || []].sort(
94
92
  (a, b) => a.order - b.order
95
93
  );
@@ -191,10 +189,10 @@ const Header = ({
191
189
  NavigationHeaderWrapper,
192
190
  {
193
191
  className: cn(
192
+ `header-${id}`,
194
193
  "relative",
195
194
  isFixed ? "fixed top-0 left-0 right-0 z-50" : "absolute top-0 left-0 right-0 z-50"
196
195
  ),
197
- style: { margin: marginValue },
198
196
  "data-container": containerBehavior,
199
197
  children: navbarWithContainer2
200
198
  }
@@ -203,11 +201,10 @@ const Header = ({
203
201
  styles && /* @__PURE__ */ jsx("style", { children: styles }),
204
202
  /* @__PURE__ */ jsxs(NavigationProvider, { children: [
205
203
  headerContent2,
206
- safeZoneHeight && safeZoneHeight !== "0" && /* @__PURE__ */ jsx(
204
+ hasSafeZone && /* @__PURE__ */ jsx(
207
205
  "div",
208
206
  {
209
- className: "header-safe-zone bg-surface",
210
- style: { height: safeZoneHeight },
207
+ className: `header-safe-zone-${id} bg-surface`,
211
208
  "aria-hidden": "true"
212
209
  }
213
210
  )
@@ -276,10 +273,10 @@ const Header = ({
276
273
  NavigationHeaderWrapper,
277
274
  {
278
275
  className: cn(
276
+ `header-${id}`,
279
277
  "relative",
280
278
  isFixed ? "fixed top-0 left-0 right-0 z-50" : "absolute top-0 left-0 right-0 z-50"
281
279
  ),
282
- style: { margin: marginValue },
283
280
  "data-container": containerBehavior,
284
281
  children: navbarWithContainer
285
282
  }
@@ -288,11 +285,10 @@ const Header = ({
288
285
  styles && /* @__PURE__ */ jsx("style", { children: styles }),
289
286
  /* @__PURE__ */ jsxs(NavigationProvider, { children: [
290
287
  headerContent,
291
- safeZoneHeight && safeZoneHeight !== "0" && /* @__PURE__ */ jsx(
288
+ hasSafeZone && /* @__PURE__ */ jsx(
292
289
  "div",
293
290
  {
294
- className: "header-safe-zone bg-surface",
295
- style: { height: safeZoneHeight },
291
+ className: `header-safe-zone-${id} bg-surface`,
296
292
  "aria-hidden": "true"
297
293
  }
298
294
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/navigation/header.tsx"],"sourcesContent":["import {\n ColorReference,\n Site,\n HeaderConfig,\n HeaderNavigationItem,\n HeaderNavigationItemConfig,\n} from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport { NavigationProvider } from \"../../context/navigation-context\";\nimport {\n cn,\n resolveColorToCSS,\n resolveColorsToCSS,\n} from \"@otl-core/style-utils\";\nimport {\n calculateNavigationWidth,\n generateNavigationCSS,\n getBreakpointForWidth,\n sectionsToDropdownContent,\n} from \"../../lib/navigation.utils\";\nimport { NavigationHeaderWrapper } from \"../mobile/navigation-header-wrapper\";\nimport { NavigationDropdown } from \"./dropdown\";\nimport { Navbar } from \"./navbar\";\n\nconst SHOW_CLASSES = {\n sm: \"hidden sm:flex\",\n md: \"hidden md:flex\",\n lg: \"hidden lg:flex\",\n xl: \"hidden xl:flex\",\n \"2xl\": \"hidden 2xl:flex\",\n} as const;\n\nconst HIDE_CLASSES = {\n sm: \"sm:hidden\",\n md: \"md:hidden\",\n lg: \"lg:hidden\",\n xl: \"xl:hidden\",\n \"2xl\": \"2xl:hidden\",\n} as const;\n\ninterface NavigationHeaderProps {\n navigation: HeaderConfig;\n site: Site;\n className?: string;\n siteName?: string;\n id?: string;\n}\n\nexport const Header: React.FC<NavigationHeaderProps> = ({\n navigation,\n site = {\n default_locale: \"en\",\n supported_locales: [\"en\"],\n } as Site,\n className = \"\",\n siteName: _siteName = \"Logo\",\n id = \"default\",\n}) => {\n const isFixed = navigation.style?.position === \"fixed\";\n const containerBehavior = navigation.style?.container || \"edged\";\n const safeZone = navigation.style?.safeZone;\n const safeZoneHeight =\n typeof safeZone === \"object\" && \"base\" in safeZone\n ? safeZone.base\n : safeZone || \"0\";\n\n const estimatedWidth = calculateNavigationWidth(\n navigation.sections || [],\n site,\n );\n const breakpoint = getBreakpointForWidth(estimatedWidth);\n\n const styleType = navigation.style?.type || \"default\";\n\n const showClass = breakpoint ? SHOW_CLASSES[breakpoint] : \"\";\n const hideClass = breakpoint ? HIDE_CLASSES[breakpoint] : \"\";\n\n const resolvedColors: Record<string, string | undefined> = navigation.style\n ? {\n ...resolveColorsToCSS(\n Object.fromEntries(\n Object.entries(navigation.style).filter(\n ([key]) =>\n key !== \"type\" &&\n key !== \"position\" &&\n key !== \"container\" &&\n key !== \"safeZone\" &&\n key !== \"layout\" &&\n key !== \"border\" &&\n key !== \"shadow\" &&\n key !== \"link\" &&\n key !== \"burger\" &&\n key !== \"dropdown\" &&\n key !== \"background\" &&\n key !== \"text\",\n ),\n ) as Record<string, ColorReference | undefined>,\n ),\n // Manually resolve background and text colors\n background: resolveColorToCSS(navigation.style.background),\n text: resolveColorToCSS(navigation.style.text),\n // Manually resolve link colors\n linkColor: resolveColorToCSS(navigation.style.link?.color),\n linkHoverColor: resolveColorToCSS(navigation.style.link?.hoverColor),\n // Manually resolve burger colors\n burgerButtonBackground: resolveColorToCSS(\n navigation.style.burger?.button?.background,\n ),\n burgerButtonBackgroundHover: resolveColorToCSS(\n navigation.style.burger?.button?.backgroundHover,\n ),\n burgerIconColor: resolveColorToCSS(\n navigation.style.burger?.icon?.color,\n ),\n burgerIconHover: resolveColorToCSS(\n navigation.style.burger?.icon?.hoverColor,\n ),\n }\n : {};\n\n const headerStyles: React.CSSProperties = {\n ...(resolvedColors.background && {\n backgroundColor: resolvedColors.background,\n }),\n ...(resolvedColors.text && {\n color: resolvedColors.text,\n }),\n };\n\n const linkStyle: React.CSSProperties = {\n ...(resolvedColors.linkColor && { color: resolvedColors.linkColor }),\n };\n\n // Extract margin for inline styles\n const marginValue =\n typeof navigation.style?.layout?.margin === \"object\" &&\n \"base\" in navigation.style.layout.margin\n ? navigation.style.layout.margin.base\n : navigation.style?.layout?.margin || \"0\";\n\n const sortedSections = [...(navigation.sections || [])].sort(\n (a, b) => a.order - b.order,\n );\n\n // Determine which section should have the toggler\n let togglerSectionId = navigation.togglerSectionId;\n\n // \"none\" means explicitly no mobile toggler at all\n if (togglerSectionId === \"none\") {\n togglerSectionId = \"\";\n } else if (!togglerSectionId) {\n // If no togglerSectionId specified, auto-assign to last non-logo section if there's content\n const hasContent = sortedSections.some((section) =>\n section.items?.some((item: HeaderNavigationItem) => item.type !== \"logo\"),\n );\n\n if (hasContent) {\n const nonLogoSections = sortedSections.filter(\n (section) =>\n !section.items?.some(\n (item: HeaderNavigationItem) => item.type === \"logo\",\n ),\n );\n\n if (nonLogoSections.length > 0) {\n togglerSectionId = nonLogoSections[nonLogoSections.length - 1].id;\n }\n }\n }\n\n const dropdownItems: Array<{\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }> = [];\n sortedSections.forEach((section) => {\n section.items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"dropdown\") {\n dropdownItems.push({\n item: item,\n config: item.config || {},\n });\n }\n });\n });\n\n // Collect all dropdown IDs for CSS generation (including mobile menu)\n const dropdownIds = [\n `mobile-menu-${id}`,\n ...(dropdownItems || []).map((d) => d.item.id),\n ];\n\n // Generate all CSS once at the header level\n const styles = generateNavigationCSS(\n id,\n navigation,\n resolvedColors,\n dropdownIds,\n );\n\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n if (styleType === \"minimal\") {\n // Minimal mode: All items render in navbar, but items without collapse:false get \"hidden\" class\n // This means only logo and collapse:false items are VISIBLE\n const navbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass=\"hidden\" // All items hidden by default in minimal mode\n togglerHideClass=\"\" // Always show toggler in minimal mode\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(({ item, config }) => (\n <NavigationDropdown\n key={item.id}\n itemId={item.id}\n config={config}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ))}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {navbarAndDropdowns}\n </div>\n ) : (\n navbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n style={{ margin: marginValue }}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {safeZoneHeight && safeZoneHeight !== \"0\" && (\n <div\n className=\"header-safe-zone bg-surface\"\n style={{ height: safeZoneHeight }}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n }\n\n const defaultNavbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass={showClass}\n togglerHideClass={hideClass}\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(\n ({\n item,\n config,\n }: {\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }) => (\n <NavigationDropdown\n config={config}\n key={item.id}\n itemId={item.id}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ),\n )}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {defaultNavbarAndDropdowns}\n </div>\n ) : (\n defaultNavbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n style={{ margin: marginValue }}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {safeZoneHeight && safeZoneHeight !== \"0\" && (\n <div\n className=\"header-safe-zone bg-surface\"\n style={{ height: safeZoneHeight }}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n};\n"],"mappings":"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","names":["navbarContent","navbarWithContainer","headerContent"]}
1
+ {"version":3,"sources":["../../../src/components/navigation/header.tsx"],"sourcesContent":["import {\n ColorReference,\n Site,\n HeaderConfig,\n HeaderNavigationItem,\n HeaderNavigationItemConfig,\n} from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport { NavigationProvider } from \"../../context/navigation-context\";\nimport {\n cn,\n resolveColorToCSS,\n resolveColorsToCSS,\n} from \"@otl-core/style-utils\";\nimport {\n calculateNavigationWidth,\n generateNavigationCSS,\n getBreakpointForWidth,\n sectionsToDropdownContent,\n} from \"../../lib/navigation.utils\";\nimport { NavigationHeaderWrapper } from \"../mobile/navigation-header-wrapper\";\nimport { NavigationDropdown } from \"./dropdown\";\nimport { Navbar } from \"./navbar\";\n\nconst SHOW_CLASSES = {\n sm: \"hidden sm:flex\",\n md: \"hidden md:flex\",\n lg: \"hidden lg:flex\",\n xl: \"hidden xl:flex\",\n \"2xl\": \"hidden 2xl:flex\",\n} as const;\n\nconst HIDE_CLASSES = {\n sm: \"sm:hidden\",\n md: \"md:hidden\",\n lg: \"lg:hidden\",\n xl: \"xl:hidden\",\n \"2xl\": \"2xl:hidden\",\n} as const;\n\ninterface NavigationHeaderProps {\n navigation: HeaderConfig;\n site: Site;\n className?: string;\n siteName?: string;\n id?: string;\n}\n\nexport const Header: React.FC<NavigationHeaderProps> = ({\n navigation,\n site = {\n default_locale: \"en\",\n supported_locales: [\"en\"],\n } as Site,\n className = \"\",\n siteName: _siteName = \"Logo\",\n id = \"default\",\n}) => {\n const isFixed = navigation.style?.position === \"fixed\";\n const containerBehavior = navigation.style?.container || \"edged\";\n const hasSafeZone = !!navigation.style?.safeZone;\n\n const estimatedWidth = calculateNavigationWidth(\n navigation.sections || [],\n site,\n );\n const breakpoint = getBreakpointForWidth(estimatedWidth);\n\n const styleType = navigation.style?.type || \"default\";\n\n const showClass = breakpoint ? SHOW_CLASSES[breakpoint] : \"\";\n const hideClass = breakpoint ? HIDE_CLASSES[breakpoint] : \"\";\n\n const resolvedColors: Record<string, string | undefined> = navigation.style\n ? {\n ...resolveColorsToCSS(\n Object.fromEntries(\n Object.entries(navigation.style).filter(\n ([key]) =>\n key !== \"type\" &&\n key !== \"position\" &&\n key !== \"container\" &&\n key !== \"safeZone\" &&\n key !== \"layout\" &&\n key !== \"border\" &&\n key !== \"shadow\" &&\n key !== \"link\" &&\n key !== \"burger\" &&\n key !== \"dropdown\" &&\n key !== \"background\" &&\n key !== \"text\",\n ),\n ) as Record<string, ColorReference | undefined>,\n ),\n // Manually resolve background and text colors\n background: resolveColorToCSS(navigation.style.background),\n text: resolveColorToCSS(navigation.style.text),\n // Manually resolve link colors\n linkColor: resolveColorToCSS(navigation.style.link?.color),\n linkHoverColor: resolveColorToCSS(navigation.style.link?.hoverColor),\n // Manually resolve burger colors\n burgerButtonBackground: resolveColorToCSS(\n navigation.style.burger?.button?.background,\n ),\n burgerButtonBackgroundHover: resolveColorToCSS(\n navigation.style.burger?.button?.backgroundHover,\n ),\n burgerIconColor: resolveColorToCSS(\n navigation.style.burger?.icon?.color,\n ),\n burgerIconHover: resolveColorToCSS(\n navigation.style.burger?.icon?.hoverColor,\n ),\n }\n : {};\n\n const headerStyles: React.CSSProperties = {\n ...(resolvedColors.background && {\n backgroundColor: resolvedColors.background,\n }),\n ...(resolvedColors.text && {\n color: resolvedColors.text,\n }),\n };\n\n const linkStyle: React.CSSProperties = {\n ...(resolvedColors.linkColor && { color: resolvedColors.linkColor }),\n };\n\n const sortedSections = [...(navigation.sections || [])].sort(\n (a, b) => a.order - b.order,\n );\n\n // Determine which section should have the toggler\n let togglerSectionId = navigation.togglerSectionId;\n\n // \"none\" means explicitly no mobile toggler at all\n if (togglerSectionId === \"none\") {\n togglerSectionId = \"\";\n } else if (!togglerSectionId) {\n // If no togglerSectionId specified, auto-assign to last non-logo section if there's content\n const hasContent = sortedSections.some((section) =>\n section.items?.some((item: HeaderNavigationItem) => item.type !== \"logo\"),\n );\n\n if (hasContent) {\n const nonLogoSections = sortedSections.filter(\n (section) =>\n !section.items?.some(\n (item: HeaderNavigationItem) => item.type === \"logo\",\n ),\n );\n\n if (nonLogoSections.length > 0) {\n togglerSectionId = nonLogoSections[nonLogoSections.length - 1].id;\n }\n }\n }\n\n const dropdownItems: Array<{\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }> = [];\n sortedSections.forEach((section) => {\n section.items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"dropdown\") {\n dropdownItems.push({\n item: item,\n config: item.config || {},\n });\n }\n });\n });\n\n // Collect all dropdown IDs for CSS generation (including mobile menu)\n const dropdownIds = [\n `mobile-menu-${id}`,\n ...(dropdownItems || []).map((d) => d.item.id),\n ];\n\n // Generate all CSS once at the header level\n const styles = generateNavigationCSS(\n id,\n navigation,\n resolvedColors,\n dropdownIds,\n );\n\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n if (styleType === \"minimal\") {\n // Minimal mode: All items render in navbar, but items without collapse:false get \"hidden\" class\n // This means only logo and collapse:false items are VISIBLE\n const navbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass=\"hidden\" // All items hidden by default in minimal mode\n togglerHideClass=\"\" // Always show toggler in minimal mode\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(({ item, config }) => (\n <NavigationDropdown\n key={item.id}\n itemId={item.id}\n config={config}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ))}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {navbarAndDropdowns}\n </div>\n ) : (\n navbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n `header-${id}`,\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {hasSafeZone && (\n <div\n className={`header-safe-zone-${id} bg-surface`}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n }\n\n const defaultNavbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass={showClass}\n togglerHideClass={hideClass}\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(\n ({\n item,\n config,\n }: {\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }) => (\n <NavigationDropdown\n config={config}\n key={item.id}\n itemId={item.id}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ),\n )}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {defaultNavbarAndDropdowns}\n </div>\n ) : (\n defaultNavbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n `header-${id}`,\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {hasSafeZone && (\n <div\n className={`header-safe-zone-${id} bg-surface`}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n};\n"],"mappings":"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","names":["navbarContent","navbarWithContainer","headerContent"]}
@@ -6,7 +6,8 @@ import {
6
6
  generateSameLayerDropdownAnimations,
7
7
  generateScrollbarStyles,
8
8
  generateToggleIconAnimations,
9
- minifyCSS
9
+ minifyCSS,
10
+ normalizeResponsiveValue
10
11
  } from "@otl-core/style-utils";
11
12
  function shadowConfigToCSS(shadow) {
12
13
  const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;
@@ -102,6 +103,18 @@ function generateNavigationCSS(id, navigation, resolvedColors, dropdownIds = [])
102
103
  const cssBlocks = [];
103
104
  const isSameLayer = navigation.style?.dropdown?.layer === "same";
104
105
  cssBlocks.push(...generateLogoCSS(id, navigation));
106
+ if (navigation.style?.layout?.margin) {
107
+ const headerMarginCSS = generateResponsiveSpacingCSS(`header-${id}`, {
108
+ margin: navigation.style.layout.margin
109
+ });
110
+ if (headerMarginCSS) cssBlocks.push(headerMarginCSS);
111
+ }
112
+ if (navigation.style?.safeZone) {
113
+ const safeZoneCSS = generateResponsiveSpacingCSS(`header-safe-zone-${id}`, {
114
+ height: navigation.style.safeZone
115
+ });
116
+ if (safeZoneCSS) cssBlocks.push(safeZoneCSS);
117
+ }
105
118
  if (navigation.style) {
106
119
  if (isSameLayer) {
107
120
  const wrapperCSS = generateResponsiveSpacingCSS(`navbar-wrapper-${id}`, {
@@ -134,6 +147,32 @@ function generateNavigationCSS(id, navigation, resolvedColors, dropdownIds = [])
134
147
  );
135
148
  }
136
149
  }
150
+ if (navigation.style?.dropdown?.offset) {
151
+ const offset = navigation.style.dropdown.offset;
152
+ const yNorm = normalizeResponsiveValue(offset.y);
153
+ const leftNorm = normalizeResponsiveValue(offset.left);
154
+ const rightNorm = normalizeResponsiveValue(offset.right);
155
+ const breakpoints = ["base", "sm", "md", "lg", "xl", "2xl"];
156
+ const compositeMargin = {};
157
+ for (const bp of breakpoints) {
158
+ const top = yNorm[bp] || (bp === "base" ? "0" : void 0);
159
+ const left = leftNorm[bp] || (bp === "base" ? "0" : void 0);
160
+ const right = rightNorm[bp] || (bp === "base" ? "0" : void 0);
161
+ if (top !== void 0 || left !== void 0 || right !== void 0) {
162
+ compositeMargin[bp] = `${top || "0"} ${right || "0"} 0 ${left || "0"}`;
163
+ }
164
+ }
165
+ if (Object.keys(compositeMargin).length > 0) {
166
+ const marginValue = compositeMargin.base ? Object.keys(compositeMargin).length === 1 ? compositeMargin.base : compositeMargin : compositeMargin;
167
+ dropdownIds.forEach((dropdownId) => {
168
+ const offsetCSS = generateResponsiveSpacingCSS(
169
+ `navigation-dropdown-${dropdownId}`,
170
+ { margin: marginValue }
171
+ );
172
+ if (offsetCSS) cssBlocks.push(offsetCSS);
173
+ });
174
+ }
175
+ }
137
176
  if (navigation.style && dropdownIds.length > 0) {
138
177
  dropdownIds.forEach((dropdownId) => {
139
178
  if (isSameLayer) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/navigation.utils.ts"],"sourcesContent":["import {\n Site,\n HeaderConfig,\n HeaderDropdownButtonConfig,\n HeaderDropdownContent,\n HeaderDropdownNavigationItemConfig,\n HeaderNavigationItem,\n HeaderNavigationItemButtonConfig,\n HeaderNavigationItemDropdownConfig,\n HeaderNavigationItemImageConfig,\n HeaderNavigationItemLinkConfig,\n HeaderNavigationItemMarkdownConfig,\n HeaderSection,\n LocalizedString,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { marked } from \"marked\";\nimport {\n generateDesktopDropdownAnimations,\n generateMobileMenuAnimations,\n generateResponsiveSpacingCSS,\n generateSameLayerDropdownAnimations,\n generateScrollbarStyles,\n generateToggleIconAnimations,\n minifyCSS,\n} from \"@otl-core/style-utils\";\n\n/**\n * Convert ShadowConfig to CSS box-shadow string\n */\nexport function shadowConfigToCSS(shadow: ShadowConfig): string {\n const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;\n const parts = [offsetX, offsetY, blurRadius, spreadRadius, color];\n if (inset) {\n return `inset ${parts.join(\" \")}`;\n }\n return parts.join(\" \");\n}\n\nexport function calculateNavigationWidth(\n sections: HeaderSection[],\n site?: Site,\n): number {\n let totalWidth = 150;\n\n for (const section of sections) {\n for (const item of section?.items || []) {\n if (item.type === \"logo\") continue;\n\n const label =\n typeof item.label === \"string\"\n ? item.label\n : getLocalizedString(item.label, site) || \"\";\n const labelLength = label.length;\n\n if (item.type === \"button\") {\n totalWidth += labelLength * 8 + 48;\n } else if (\n item.type === \"link\" ||\n item.type === \"dropdown\" ||\n item.type === \"markdown\"\n ) {\n totalWidth += labelLength * 8 + 24;\n } else if (item.type === \"image\") {\n const imgConfig = item.config as { width?: string };\n const imgWidth = imgConfig?.width\n ? parseInt(imgConfig.width, 10) || 100\n : 100;\n totalWidth += imgWidth + 16;\n }\n }\n }\n\n return totalWidth;\n}\n\nexport type Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | null;\n\nexport function getBreakpointForWidth(estimatedWidth: number): Breakpoint {\n const MAX_USABLE_WIDTH = 1400;\n\n if (estimatedWidth > MAX_USABLE_WIDTH) return null;\n\n if (estimatedWidth <= 640) return \"sm\";\n if (estimatedWidth <= 768) return \"md\";\n if (estimatedWidth <= 1024) return \"lg\";\n if (estimatedWidth <= 1280) return \"xl\";\n return \"2xl\";\n}\n\nconst RESPONSIVE_BREAKPOINTS = [\n { key: \"sm\", minWidth: \"640px\" },\n { key: \"md\", minWidth: \"768px\" },\n { key: \"lg\", minWidth: \"1024px\" },\n { key: \"xl\", minWidth: \"1280px\" },\n] as const;\n\nfunction generateResponsiveCustomProps(\n className: string,\n props: Record<string, ResponsiveValue<string> | undefined>,\n): string[] {\n const css: string[] = [];\n const baseVars: string[] = [];\n const bpVars: Record<string, string[]> = {};\n\n for (const [prop, value] of Object.entries(props)) {\n if (!value) continue;\n if (typeof value === \"string\") {\n baseVars.push(`${prop}:${value}`);\n } else {\n if (value.base) baseVars.push(`${prop}:${value.base}`);\n for (const { key } of RESPONSIVE_BREAKPOINTS) {\n const bpVal = value[key as keyof typeof value];\n if (bpVal && typeof bpVal === \"string\") {\n if (!bpVars[key]) bpVars[key] = [];\n bpVars[key].push(`${prop}:${bpVal}`);\n }\n }\n }\n }\n\n const target = `.${className}`;\n if (baseVars.length > 0) {\n css.push(`${target}{${baseVars.join(\";\")}}`);\n }\n for (const { key, minWidth } of RESPONSIVE_BREAKPOINTS) {\n if (bpVars[key]?.length) {\n css.push(\n `@media(min-width:${minWidth}){${target}{${bpVars[key].join(\";\")}}}`,\n );\n }\n }\n return css;\n}\n\n/**\n * Normalize a logo size value (responsive, plain string, or legacy\n * numeric pixels) into a ResponsiveValue<string>.\n */\nfunction normalizeLogoSize(\n value: ResponsiveValue<string> | number | undefined,\n): ResponsiveValue<string> | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"number\") return { base: `${value}px` };\n if (typeof value === \"string\") return { base: value };\n return value;\n}\n\nfunction generateLogoCSS(id: string, navigation: HeaderConfig): string[] {\n if (!navigation.logo?.url) return [];\n const width = normalizeLogoSize(navigation.logo.width) ?? { base: \"auto\" };\n const height = normalizeLogoSize(navigation.logo.height) ?? { base: \"40px\" };\n return generateResponsiveCustomProps(`navbar-${id} .navigation-logo-img`, {\n width,\n height,\n });\n}\n\nexport function generateNavigationCSS(\n id: string,\n navigation: HeaderConfig,\n resolvedColors: Record<string, string | undefined>,\n dropdownIds: string[] = [],\n): string {\n const cssBlocks: (string | null)[] = [];\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n cssBlocks.push(...generateLogoCSS(id, navigation));\n\n // Margins are now applied inline, no CSS generation needed\n\n if (navigation.style) {\n if (isSameLayer) {\n // Same layer: navbar wrapper gets border/padding/shadow, navbar itself only gets inner styles\n const wrapperCSS = generateResponsiveSpacingCSS(`navbar-wrapper-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (wrapperCSS) cssBlocks.push(wrapperCSS);\n } else {\n const navbarCSS = generateResponsiveSpacingCSS(`navbar-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (navbarCSS) cssBlocks.push(navbarCSS);\n }\n\n const navbarInnerCSS = generateResponsiveSpacingCSS(`navbar-inner-${id}`, {\n gap: navigation.style.layout?.sectionGap,\n fontSize: navigation.style.fontSize?.navbar,\n });\n if (navbarInnerCSS) cssBlocks.push(navbarInnerCSS);\n\n const btnFontSize = navigation.style.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`navbar-inner-${id}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n }\n\n if (navigation.style && dropdownIds.length > 0) {\n dropdownIds.forEach((dropdownId) => {\n if (isSameLayer) {\n // Same layer: dropdown only gets gap/fontSize, no border/padding/shadow (inherited from wrapper)\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n } else {\n const dropdownCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n {\n padding: navigation.style?.dropdown?.padding,\n border: navigation.style?.dropdown?.border,\n shadow: navigation.style?.dropdown?.shadow,\n },\n );\n if (dropdownCSS) cssBlocks.push(dropdownCSS);\n\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n }\n\n const btnFontSize = navigation.style?.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`dropdown-content-${dropdownId}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n });\n }\n\n if (resolvedColors.burgerButtonBackgroundHover) {\n cssBlocks.push(\n `.mobile-menu-toggle-${id}:hover{background-color:${resolvedColors.burgerButtonBackgroundHover}!important}`,\n );\n }\n\n if (\n resolvedColors.dropdownMenuLinkHoverColor ||\n resolvedColors.dropdownMenuLinkHoverBackground\n ) {\n const hoverStyles: string[] = [];\n if (resolvedColors.dropdownMenuLinkHoverBackground) {\n hoverStyles.push(\n `background-color:${resolvedColors.dropdownMenuLinkHoverBackground}!important`,\n );\n }\n if (resolvedColors.dropdownMenuLinkHoverColor) {\n hoverStyles.push(\n `color:${resolvedColors.dropdownMenuLinkHoverColor}!important`,\n );\n }\n cssBlocks.push(\n `#mobile-menu-dropdown-${id} a:hover{${hoverStyles.join(\";\")}}`,\n );\n }\n\n cssBlocks.push(...generateToggleIconAnimations());\n cssBlocks.push(...generateMobileMenuAnimations());\n cssBlocks.push(...generateScrollbarStyles());\n cssBlocks.push(...generateDesktopDropdownAnimations());\n if (isSameLayer) {\n cssBlocks.push(...generateSameLayerDropdownAnimations());\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\nexport function sectionsToDropdownContent(\n sections: HeaderSection[],\n): HeaderDropdownContent[] {\n const result: HeaderDropdownContent[] = [];\n let lastSectionHadContent = false;\n\n sections.forEach((section: HeaderSection, index: number) => {\n const items = section?.items?.filter((item: HeaderNavigationItem) => {\n if (item.type === \"logo\") return false;\n if (resolveItemVisibility(item) === \"navbar-only\") return false;\n return true;\n });\n\n if (items?.length === 0) {\n return; // Skip this section, don't update lastSectionHadContent\n }\n\n // Add divider if the previous section had content and this isn't the first section with content\n if (lastSectionHadContent && result.length > 0) {\n result.push({\n id: `divider-${sections[index - 1].id}`,\n type: \"divider\",\n config: {},\n });\n }\n\n items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"link\") {\n const config = item.config as HeaderNavigationItemLinkConfig;\n const navConfig: HeaderDropdownNavigationItemConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n };\n result.push({\n id: item.id,\n type: \"navigation-item\",\n config: navConfig,\n });\n } else if (item.type === \"button\") {\n const config = item.config as HeaderNavigationItemButtonConfig;\n const btnConfig: HeaderDropdownButtonConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n variant: config.variant,\n size: config.size,\n };\n result.push({\n id: item.id,\n type: \"button\",\n config: btnConfig,\n });\n } else if (item.type === \"dropdown\") {\n const config = item.config as HeaderNavigationItemDropdownConfig;\n result.push({\n id: item.id,\n type: \"dropdown\",\n label: item.label || \"\",\n config,\n });\n } else if (item.type === \"markdown\") {\n const config = item.config as HeaderNavigationItemMarkdownConfig;\n result.push({\n id: item.id,\n type: \"markdown\",\n config: { content: config.content || item.label || \"\" },\n });\n } else if (item.type === \"image\") {\n const config = item.config as HeaderNavigationItemImageConfig;\n result.push({\n id: item.id,\n type: \"image\",\n config: {\n src: config.src,\n alt: config.alt,\n width: config.width ? { base: config.width } : { base: \"100%\" },\n height: config.height ? { base: config.height } : { base: \"auto\" },\n objectFit: config.objectFit,\n href: config.href,\n },\n });\n }\n });\n\n lastSectionHadContent = true;\n });\n\n return result;\n}\n\nexport function resolveDropdownColor(\n colorRef: { type: string; value: string } | undefined,\n resolvedColors: Record<string, string | undefined>,\n fallback?: string,\n): string | undefined {\n if (!colorRef) return fallback;\n\n if (colorRef.type === \"custom\") {\n return colorRef.value;\n }\n\n if (colorRef.type === \"theme\") {\n return resolvedColors[colorRef.value] || fallback;\n }\n\n if (colorRef.type === \"variable\") {\n // For variables, construct the CSS variable reference\n return `var(--color-${colorRef.value})`;\n }\n\n return fallback;\n}\n\nfunction getBrowserPreferredLocales(options = {}) {\n const defaultOptions = {\n languageCodeOnly: false,\n };\n const opt = {\n ...defaultOptions,\n ...options,\n };\n const browserLocales =\n navigator.languages === undefined\n ? [navigator.language]\n : navigator.languages;\n if (!browserLocales) {\n return undefined;\n }\n return browserLocales.map((locale) => {\n const trimmedLocale = locale.trim();\n return opt.languageCodeOnly ? trimmedLocale.split(/-|_/)[0] : trimmedLocale;\n });\n}\n\nexport function getLocalizedString(\n value: string | LocalizedString | null | undefined,\n options?:\n | Site\n | {\n preferredLocale?: string;\n defaultLocale?: string;\n supportedLocales?: string[];\n },\n): string {\n // Handle null/undefined\n if (value === null || value === undefined) return \"\";\n\n // If it's already a string, return it\n if (typeof value === \"string\") return value;\n\n // Normalize options to handle both Site and simple options object\n const preferredLocale =\n options && \"preferredLocale\" in options\n ? options.preferredLocale\n : undefined;\n function getDefaultLocale(): string | undefined {\n if (options && \"defaultLocale\" in options) return options.defaultLocale;\n if (options && \"default_locale\" in options) return options.default_locale;\n return undefined;\n }\n function getSupportedLocales(): string[] | undefined {\n if (options && \"supportedLocales\" in options)\n return options.supportedLocales;\n if (options && \"supported_locales\" in options)\n return options.supported_locales;\n return undefined;\n }\n const defaultLocale = getDefaultLocale();\n const supportedLocales = getSupportedLocales();\n\n // Try preferred locale first (if explicitly provided)\n if (preferredLocale && preferredLocale in value && value[preferredLocale]) {\n return value[preferredLocale];\n }\n\n // Try browser locales if no explicit preferred locale\n if (!preferredLocale) {\n const browserLocales = getBrowserPreferredLocales();\n if (browserLocales) {\n for (const locale of browserLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n }\n\n // Try default locale\n if (defaultLocale && defaultLocale in value && value[defaultLocale]) {\n return value[defaultLocale];\n }\n\n // Try 'en' as fallback\n if (\"en\" in value && value.en) {\n return value.en;\n }\n\n // Try any supported locale\n if (supportedLocales) {\n for (const locale of supportedLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n\n // Return first available value as last resort\n const keys = Object.keys(value);\n if (keys.length > 0 && value[keys[0]]) {\n return value[keys[0]];\n }\n\n return \"\";\n}\n\n/**\n * Resolve the effective visibility for a navigation item.\n * Supports the new `visibility` field and the legacy `collapse` field.\n * collapse: false → \"navbar-only\", collapse: true/undefined → \"responsive\"\n */\nexport function resolveItemVisibility(\n item: HeaderNavigationItem,\n): HeaderNavigationItem[\"visibility\"] {\n if (item.visibility) return item.visibility;\n const legacy = (item as unknown as Record<string, unknown>).collapse;\n if (legacy === false) return \"navbar-only\";\n return undefined;\n}\n\nconst VISIBILITY_CLASSES: Record<string, string> = {\n \"navbar-only\": \"flex\",\n \"mobile-only\": \"hidden\",\n both: \"flex\",\n};\n\n/**\n * Get the CSS class for an item's visibility, falling back to the\n * responsive breakpoint class when no explicit visibility is set.\n */\nexport function getVisibilityClass(\n item: HeaderNavigationItem,\n fallback?: string,\n): string {\n const vis = resolveItemVisibility(item);\n return (vis && VISIBILITY_CLASSES[vis]) || fallback || \"\";\n}\n\nexport function parseMarkdownToHTML(markdown: string): string {\n // Parse markdown to HTML\n const html = marked.parse(markdown, { async: false }) as string;\n\n // Transform h1-h6 elements to divs with corresponding classes\n return html\n .replace(/<h1>/g, '<div class=\"h1\">')\n .replace(/<\\/h1>/g, \"</div>\")\n .replace(/<h2>/g, '<div class=\"h2\">')\n .replace(/<\\/h2>/g, \"</div>\")\n .replace(/<h3>/g, '<div class=\"h3\">')\n .replace(/<\\/h3>/g, \"</div>\")\n .replace(/<h4>/g, '<div class=\"h4\">')\n .replace(/<\\/h4>/g, \"</div>\")\n .replace(/<h5>/g, '<div class=\"h5\">')\n .replace(/<\\/h5>/g, \"</div>\")\n .replace(/<h6>/g, '<div class=\"h6\">')\n .replace(/<\\/h6>/g, \"</div>\");\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/lib/navigation.utils.ts"],"sourcesContent":["import {\n Site,\n HeaderConfig,\n HeaderDropdownButtonConfig,\n HeaderDropdownContent,\n HeaderDropdownNavigationItemConfig,\n HeaderNavigationItem,\n HeaderNavigationItemButtonConfig,\n HeaderNavigationItemDropdownConfig,\n HeaderNavigationItemImageConfig,\n HeaderNavigationItemLinkConfig,\n HeaderNavigationItemMarkdownConfig,\n HeaderSection,\n LocalizedString,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { marked } from \"marked\";\nimport {\n generateDesktopDropdownAnimations,\n generateMobileMenuAnimations,\n generateResponsiveSpacingCSS,\n generateSameLayerDropdownAnimations,\n generateScrollbarStyles,\n generateToggleIconAnimations,\n minifyCSS,\n normalizeResponsiveValue,\n} from \"@otl-core/style-utils\";\n\n/**\n * Convert ShadowConfig to CSS box-shadow string\n */\nexport function shadowConfigToCSS(shadow: ShadowConfig): string {\n const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;\n const parts = [offsetX, offsetY, blurRadius, spreadRadius, color];\n if (inset) {\n return `inset ${parts.join(\" \")}`;\n }\n return parts.join(\" \");\n}\n\nexport function calculateNavigationWidth(\n sections: HeaderSection[],\n site?: Site,\n): number {\n let totalWidth = 150;\n\n for (const section of sections) {\n for (const item of section?.items || []) {\n if (item.type === \"logo\") continue;\n\n const label =\n typeof item.label === \"string\"\n ? item.label\n : getLocalizedString(item.label, site) || \"\";\n const labelLength = label.length;\n\n if (item.type === \"button\") {\n totalWidth += labelLength * 8 + 48;\n } else if (\n item.type === \"link\" ||\n item.type === \"dropdown\" ||\n item.type === \"markdown\"\n ) {\n totalWidth += labelLength * 8 + 24;\n } else if (item.type === \"image\") {\n const imgConfig = item.config as { width?: string };\n const imgWidth = imgConfig?.width\n ? parseInt(imgConfig.width, 10) || 100\n : 100;\n totalWidth += imgWidth + 16;\n }\n }\n }\n\n return totalWidth;\n}\n\nexport type Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | null;\n\nexport function getBreakpointForWidth(estimatedWidth: number): Breakpoint {\n const MAX_USABLE_WIDTH = 1400;\n\n if (estimatedWidth > MAX_USABLE_WIDTH) return null;\n\n if (estimatedWidth <= 640) return \"sm\";\n if (estimatedWidth <= 768) return \"md\";\n if (estimatedWidth <= 1024) return \"lg\";\n if (estimatedWidth <= 1280) return \"xl\";\n return \"2xl\";\n}\n\nconst RESPONSIVE_BREAKPOINTS = [\n { key: \"sm\", minWidth: \"640px\" },\n { key: \"md\", minWidth: \"768px\" },\n { key: \"lg\", minWidth: \"1024px\" },\n { key: \"xl\", minWidth: \"1280px\" },\n] as const;\n\nfunction generateResponsiveCustomProps(\n className: string,\n props: Record<string, ResponsiveValue<string> | undefined>,\n): string[] {\n const css: string[] = [];\n const baseVars: string[] = [];\n const bpVars: Record<string, string[]> = {};\n\n for (const [prop, value] of Object.entries(props)) {\n if (!value) continue;\n if (typeof value === \"string\") {\n baseVars.push(`${prop}:${value}`);\n } else {\n if (value.base) baseVars.push(`${prop}:${value.base}`);\n for (const { key } of RESPONSIVE_BREAKPOINTS) {\n const bpVal = value[key as keyof typeof value];\n if (bpVal && typeof bpVal === \"string\") {\n if (!bpVars[key]) bpVars[key] = [];\n bpVars[key].push(`${prop}:${bpVal}`);\n }\n }\n }\n }\n\n const target = `.${className}`;\n if (baseVars.length > 0) {\n css.push(`${target}{${baseVars.join(\";\")}}`);\n }\n for (const { key, minWidth } of RESPONSIVE_BREAKPOINTS) {\n if (bpVars[key]?.length) {\n css.push(\n `@media(min-width:${minWidth}){${target}{${bpVars[key].join(\";\")}}}`,\n );\n }\n }\n return css;\n}\n\n/**\n * Normalize a logo size value (responsive, plain string, or legacy\n * numeric pixels) into a ResponsiveValue<string>.\n */\nfunction normalizeLogoSize(\n value: ResponsiveValue<string> | number | undefined,\n): ResponsiveValue<string> | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"number\") return { base: `${value}px` };\n if (typeof value === \"string\") return { base: value };\n return value;\n}\n\nfunction generateLogoCSS(id: string, navigation: HeaderConfig): string[] {\n if (!navigation.logo?.url) return [];\n const width = normalizeLogoSize(navigation.logo.width) ?? { base: \"auto\" };\n const height = normalizeLogoSize(navigation.logo.height) ?? { base: \"40px\" };\n return generateResponsiveCustomProps(`navbar-${id} .navigation-logo-img`, {\n width,\n height,\n });\n}\n\nexport function generateNavigationCSS(\n id: string,\n navigation: HeaderConfig,\n resolvedColors: Record<string, string | undefined>,\n dropdownIds: string[] = [],\n): string {\n const cssBlocks: (string | null)[] = [];\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n cssBlocks.push(...generateLogoCSS(id, navigation));\n\n if (navigation.style?.layout?.margin) {\n const headerMarginCSS = generateResponsiveSpacingCSS(`header-${id}`, {\n margin: navigation.style.layout.margin,\n });\n if (headerMarginCSS) cssBlocks.push(headerMarginCSS);\n }\n\n if (navigation.style?.safeZone) {\n const safeZoneCSS = generateResponsiveSpacingCSS(`header-safe-zone-${id}`, {\n height: navigation.style.safeZone,\n });\n if (safeZoneCSS) cssBlocks.push(safeZoneCSS);\n }\n\n if (navigation.style) {\n if (isSameLayer) {\n // Same layer: navbar wrapper gets border/padding/shadow, navbar itself only gets inner styles\n const wrapperCSS = generateResponsiveSpacingCSS(`navbar-wrapper-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (wrapperCSS) cssBlocks.push(wrapperCSS);\n } else {\n const navbarCSS = generateResponsiveSpacingCSS(`navbar-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (navbarCSS) cssBlocks.push(navbarCSS);\n }\n\n const navbarInnerCSS = generateResponsiveSpacingCSS(`navbar-inner-${id}`, {\n gap: navigation.style.layout?.sectionGap,\n fontSize: navigation.style.fontSize?.navbar,\n });\n if (navbarInnerCSS) cssBlocks.push(navbarInnerCSS);\n\n const btnFontSize = navigation.style.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`navbar-inner-${id}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n }\n\n // Generate responsive offset margin for all dropdowns\n if (navigation.style?.dropdown?.offset) {\n const offset = navigation.style.dropdown.offset;\n const yNorm = normalizeResponsiveValue(offset.y);\n const leftNorm = normalizeResponsiveValue(offset.left);\n const rightNorm = normalizeResponsiveValue(offset.right);\n const breakpoints = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\"] as const;\n const compositeMargin: Record<string, string> = {};\n for (const bp of breakpoints) {\n const top = yNorm[bp] || (bp === \"base\" ? \"0\" : undefined);\n const left = leftNorm[bp] || (bp === \"base\" ? \"0\" : undefined);\n const right = rightNorm[bp] || (bp === \"base\" ? \"0\" : undefined);\n if (top !== undefined || left !== undefined || right !== undefined) {\n compositeMargin[bp] = `${top || \"0\"} ${right || \"0\"} 0 ${left || \"0\"}`;\n }\n }\n if (Object.keys(compositeMargin).length > 0) {\n const marginValue = compositeMargin.base\n ? Object.keys(compositeMargin).length === 1\n ? compositeMargin.base\n : compositeMargin\n : compositeMargin;\n dropdownIds.forEach((dropdownId) => {\n const offsetCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n { margin: marginValue as ResponsiveValue<string> },\n );\n if (offsetCSS) cssBlocks.push(offsetCSS);\n });\n }\n }\n\n if (navigation.style && dropdownIds.length > 0) {\n dropdownIds.forEach((dropdownId) => {\n if (isSameLayer) {\n // Same layer: dropdown only gets gap/fontSize, no border/padding/shadow (inherited from wrapper)\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n } else {\n const dropdownCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n {\n padding: navigation.style?.dropdown?.padding,\n border: navigation.style?.dropdown?.border,\n shadow: navigation.style?.dropdown?.shadow,\n },\n );\n if (dropdownCSS) cssBlocks.push(dropdownCSS);\n\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n }\n\n const btnFontSize = navigation.style?.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`dropdown-content-${dropdownId}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n });\n }\n\n if (resolvedColors.burgerButtonBackgroundHover) {\n cssBlocks.push(\n `.mobile-menu-toggle-${id}:hover{background-color:${resolvedColors.burgerButtonBackgroundHover}!important}`,\n );\n }\n\n if (\n resolvedColors.dropdownMenuLinkHoverColor ||\n resolvedColors.dropdownMenuLinkHoverBackground\n ) {\n const hoverStyles: string[] = [];\n if (resolvedColors.dropdownMenuLinkHoverBackground) {\n hoverStyles.push(\n `background-color:${resolvedColors.dropdownMenuLinkHoverBackground}!important`,\n );\n }\n if (resolvedColors.dropdownMenuLinkHoverColor) {\n hoverStyles.push(\n `color:${resolvedColors.dropdownMenuLinkHoverColor}!important`,\n );\n }\n cssBlocks.push(\n `#mobile-menu-dropdown-${id} a:hover{${hoverStyles.join(\";\")}}`,\n );\n }\n\n cssBlocks.push(...generateToggleIconAnimations());\n cssBlocks.push(...generateMobileMenuAnimations());\n cssBlocks.push(...generateScrollbarStyles());\n cssBlocks.push(...generateDesktopDropdownAnimations());\n if (isSameLayer) {\n cssBlocks.push(...generateSameLayerDropdownAnimations());\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\nexport function sectionsToDropdownContent(\n sections: HeaderSection[],\n): HeaderDropdownContent[] {\n const result: HeaderDropdownContent[] = [];\n let lastSectionHadContent = false;\n\n sections.forEach((section: HeaderSection, index: number) => {\n const items = section?.items?.filter((item: HeaderNavigationItem) => {\n if (item.type === \"logo\") return false;\n if (resolveItemVisibility(item) === \"navbar-only\") return false;\n return true;\n });\n\n if (items?.length === 0) {\n return; // Skip this section, don't update lastSectionHadContent\n }\n\n // Add divider if the previous section had content and this isn't the first section with content\n if (lastSectionHadContent && result.length > 0) {\n result.push({\n id: `divider-${sections[index - 1].id}`,\n type: \"divider\",\n config: {},\n });\n }\n\n items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"link\") {\n const config = item.config as HeaderNavigationItemLinkConfig;\n const navConfig: HeaderDropdownNavigationItemConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n };\n result.push({\n id: item.id,\n type: \"navigation-item\",\n config: navConfig,\n });\n } else if (item.type === \"button\") {\n const config = item.config as HeaderNavigationItemButtonConfig;\n const btnConfig: HeaderDropdownButtonConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n variant: config.variant,\n size: config.size,\n };\n result.push({\n id: item.id,\n type: \"button\",\n config: btnConfig,\n });\n } else if (item.type === \"dropdown\") {\n const config = item.config as HeaderNavigationItemDropdownConfig;\n result.push({\n id: item.id,\n type: \"dropdown\",\n label: item.label || \"\",\n config,\n });\n } else if (item.type === \"markdown\") {\n const config = item.config as HeaderNavigationItemMarkdownConfig;\n result.push({\n id: item.id,\n type: \"markdown\",\n config: { content: config.content || item.label || \"\" },\n });\n } else if (item.type === \"image\") {\n const config = item.config as HeaderNavigationItemImageConfig;\n result.push({\n id: item.id,\n type: \"image\",\n config: {\n src: config.src,\n alt: config.alt,\n width: config.width ? { base: config.width } : { base: \"100%\" },\n height: config.height ? { base: config.height } : { base: \"auto\" },\n objectFit: config.objectFit,\n href: config.href,\n },\n });\n }\n });\n\n lastSectionHadContent = true;\n });\n\n return result;\n}\n\nexport function resolveDropdownColor(\n colorRef: { type: string; value: string } | undefined,\n resolvedColors: Record<string, string | undefined>,\n fallback?: string,\n): string | undefined {\n if (!colorRef) return fallback;\n\n if (colorRef.type === \"custom\") {\n return colorRef.value;\n }\n\n if (colorRef.type === \"theme\") {\n return resolvedColors[colorRef.value] || fallback;\n }\n\n if (colorRef.type === \"variable\") {\n // For variables, construct the CSS variable reference\n return `var(--color-${colorRef.value})`;\n }\n\n return fallback;\n}\n\nfunction getBrowserPreferredLocales(options = {}) {\n const defaultOptions = {\n languageCodeOnly: false,\n };\n const opt = {\n ...defaultOptions,\n ...options,\n };\n const browserLocales =\n navigator.languages === undefined\n ? [navigator.language]\n : navigator.languages;\n if (!browserLocales) {\n return undefined;\n }\n return browserLocales.map((locale) => {\n const trimmedLocale = locale.trim();\n return opt.languageCodeOnly ? trimmedLocale.split(/-|_/)[0] : trimmedLocale;\n });\n}\n\nexport function getLocalizedString(\n value: string | LocalizedString | null | undefined,\n options?:\n | Site\n | {\n preferredLocale?: string;\n defaultLocale?: string;\n supportedLocales?: string[];\n },\n): string {\n // Handle null/undefined\n if (value === null || value === undefined) return \"\";\n\n // If it's already a string, return it\n if (typeof value === \"string\") return value;\n\n // Normalize options to handle both Site and simple options object\n const preferredLocale =\n options && \"preferredLocale\" in options\n ? options.preferredLocale\n : undefined;\n function getDefaultLocale(): string | undefined {\n if (options && \"defaultLocale\" in options) return options.defaultLocale;\n if (options && \"default_locale\" in options) return options.default_locale;\n return undefined;\n }\n function getSupportedLocales(): string[] | undefined {\n if (options && \"supportedLocales\" in options)\n return options.supportedLocales;\n if (options && \"supported_locales\" in options)\n return options.supported_locales;\n return undefined;\n }\n const defaultLocale = getDefaultLocale();\n const supportedLocales = getSupportedLocales();\n\n // Try preferred locale first (if explicitly provided)\n if (preferredLocale && preferredLocale in value && value[preferredLocale]) {\n return value[preferredLocale];\n }\n\n // Try browser locales if no explicit preferred locale\n if (!preferredLocale) {\n const browserLocales = getBrowserPreferredLocales();\n if (browserLocales) {\n for (const locale of browserLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n }\n\n // Try default locale\n if (defaultLocale && defaultLocale in value && value[defaultLocale]) {\n return value[defaultLocale];\n }\n\n // Try 'en' as fallback\n if (\"en\" in value && value.en) {\n return value.en;\n }\n\n // Try any supported locale\n if (supportedLocales) {\n for (const locale of supportedLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n\n // Return first available value as last resort\n const keys = Object.keys(value);\n if (keys.length > 0 && value[keys[0]]) {\n return value[keys[0]];\n }\n\n return \"\";\n}\n\n/**\n * Resolve the effective visibility for a navigation item.\n * Supports the new `visibility` field and the legacy `collapse` field.\n * collapse: false → \"navbar-only\", collapse: true/undefined → \"responsive\"\n */\nexport function resolveItemVisibility(\n item: HeaderNavigationItem,\n): HeaderNavigationItem[\"visibility\"] {\n if (item.visibility) return item.visibility;\n const legacy = (item as unknown as Record<string, unknown>).collapse;\n if (legacy === false) return \"navbar-only\";\n return undefined;\n}\n\nconst VISIBILITY_CLASSES: Record<string, string> = {\n \"navbar-only\": \"flex\",\n \"mobile-only\": \"hidden\",\n both: \"flex\",\n};\n\n/**\n * Get the CSS class for an item's visibility, falling back to the\n * responsive breakpoint class when no explicit visibility is set.\n */\nexport function getVisibilityClass(\n item: HeaderNavigationItem,\n fallback?: string,\n): string {\n const vis = resolveItemVisibility(item);\n return (vis && VISIBILITY_CLASSES[vis]) || fallback || \"\";\n}\n\nexport function parseMarkdownToHTML(markdown: string): string {\n // Parse markdown to HTML\n const html = marked.parse(markdown, { async: false }) as string;\n\n // Transform h1-h6 elements to divs with corresponding classes\n return html\n .replace(/<h1>/g, '<div class=\"h1\">')\n .replace(/<\\/h1>/g, \"</div>\")\n .replace(/<h2>/g, '<div class=\"h2\">')\n .replace(/<\\/h2>/g, \"</div>\")\n .replace(/<h3>/g, '<div class=\"h3\">')\n .replace(/<\\/h3>/g, \"</div>\")\n .replace(/<h4>/g, '<div class=\"h4\">')\n .replace(/<\\/h4>/g, \"</div>\")\n .replace(/<h5>/g, '<div class=\"h5\">')\n .replace(/<\\/h5>/g, \"</div>\")\n .replace(/<h6>/g, '<div class=\"h6\">')\n .replace(/<\\/h6>/g, \"</div>\");\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otl-core/next-navigation",
3
- "version": "1.1.35",
3
+ "version": "1.1.37",
4
4
  "type": "module",
5
5
  "description": "Reusable navigation components for OTL CMS",
6
6
  "main": "./dist/index.js",
@@ -48,13 +48,13 @@
48
48
  "tailwind-merge": "^3.3.1"
49
49
  },
50
50
  "dependencies": {
51
- "@otl-core/cms-utils": "^1.1.35",
52
- "@otl-core/style-utils": "^1.1.35"
51
+ "@otl-core/cms-utils": "^1.1.37",
52
+ "@otl-core/style-utils": "^1.1.37"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@eslint/eslintrc": "^3.3.1",
56
- "@otl-core/cms-types": "^1.1.35",
57
- "@otl-core/cms-utils": "^1.1.35",
56
+ "@otl-core/cms-types": "^1.1.37",
57
+ "@otl-core/cms-utils": "^1.1.37",
58
58
  "@radix-ui/react-focus-scope": "^1.1.7",
59
59
  "@radix-ui/react-slot": "^1.2.3",
60
60
  "@testing-library/jest-dom": "^6.9.1",