@otl-core/next-navigation 1.1.37 → 1.1.39

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.
@@ -22,7 +22,10 @@ function resolveBorder(border) {
22
22
  const width = base.width ?? "0";
23
23
  const style = base.style ?? "solid";
24
24
  const color = base.color ? resolveColorToCSS(base.color) : "transparent";
25
- return `${width} ${style} ${color}`;
25
+ if (width.trim().includes(" ")) {
26
+ return `border-width: ${width}; border-style: ${style}; border-color: ${color}`;
27
+ }
28
+ return `border: ${width} ${style} ${color}`;
26
29
  }
27
30
  function generateFooterCSS(id, footer, resolvedColors) {
28
31
  const cssBlocks = [];
@@ -36,7 +39,7 @@ function generateFooterCSS(id, footer, resolvedColors) {
36
39
  ${resolvedColors.text ? `color: ${resolvedColors.text};` : ""}
37
40
  ${baseMargin ? `margin: ${baseMargin};` : ""}
38
41
  ${basePadding ? `padding: ${basePadding};` : ""}
39
- ${borderCSS ? `border: ${borderCSS};` : ""}
42
+ ${borderCSS ? `${borderCSS};` : ""}
40
43
  ${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : ""}
41
44
  }
42
45
  `;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/footer.utils.ts"],"sourcesContent":["import {\n BorderConfig,\n FooterConfig,\n FooterContentSection,\n FooterSection,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { isResponsiveConfig } from \"@otl-core/cms-utils\";\nimport { resolveColorToCSS } from \"@otl-core/style-utils\";\n\n/**\n * Resolve all colors in the footer configuration to CSS values\n */\nexport function resolveFooterColors(\n style: FooterConfig[\"style\"],\n): Record<string, string | undefined> {\n const resolved: Record<string, string | undefined> = {\n background: resolveColorToCSS(style.background),\n text: resolveColorToCSS(style.text),\n linkColor: resolveColorToCSS(style.link.color),\n linkHoverColor: resolveColorToCSS(style.link.hoverColor),\n };\n\n return resolved;\n}\n\n/**\n * Resolve a responsive value to get the base value\n */\nfunction getResponsiveBase<T>(value: ResponsiveValue<T> | T): T {\n if (typeof value === \"object\" && value !== null && \"base\" in value) {\n return value.base;\n }\n return value as T;\n}\n\n/**\n * Resolve border config to CSS string\n */\nfunction resolveBorder(\n border: ResponsiveValue<BorderConfig> | undefined,\n): string {\n if (!border) return \"\";\n\n const base = getResponsiveBase(border);\n if (!base) return \"\";\n\n const width = base.width ?? \"0\";\n const style = base.style ?? \"solid\";\n const color = base.color ? resolveColorToCSS(base.color) : \"transparent\";\n\n return `${width} ${style} ${color}`;\n}\n\n/**\n * Generate CSS for the footer configuration\n */\nexport function generateFooterCSS(\n id: string,\n footer: FooterConfig,\n resolvedColors: Record<string, string | undefined>,\n): string {\n const cssBlocks: string[] = [];\n\n // Base footer styles\n const baseMargin = getResponsiveBase(footer.style.layout.margin);\n const basePadding = getResponsiveBase(footer.style.layout.padding);\n const baseSectionGap = getResponsiveBase(footer.style.layout.sectionGap);\n const borderCSS = resolveBorder(footer.style.border);\n\n const baseStyles = `\n .footer-${id} {\n ${resolvedColors.background ? `background-color: ${resolvedColors.background};` : \"\"}\n ${resolvedColors.text ? `color: ${resolvedColors.text};` : \"\"}\n ${baseMargin ? `margin: ${baseMargin};` : \"\"}\n ${basePadding ? `padding: ${basePadding};` : \"\"}\n ${borderCSS ? `border: ${borderCSS};` : \"\"}\n ${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : \"\"}\n }\n `;\n cssBlocks.push(baseStyles);\n\n // Link styles\n if (resolvedColors.linkColor || resolvedColors.linkHoverColor) {\n cssBlocks.push(`\n .footer-${id} a {\n ${resolvedColors.linkColor ? `color: ${resolvedColors.linkColor};` : \"\"}\n text-decoration: none;\n transition: color 0.2s;\n }\n .footer-${id} a:hover {\n ${resolvedColors.linkHoverColor ? `color: ${resolvedColors.linkHoverColor};` : \"\"}\n }\n `);\n }\n\n // Section gap\n if (baseSectionGap) {\n cssBlocks.push(`\n .footer-${id} > .footer-section {\n gap: ${baseSectionGap};\n }\n `);\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\n/**\n * Format shadow config to CSS box-shadow value\n */\nfunction formatShadow(shadow: ShadowConfig): string {\n const insetStr = shadow.inset ? \"inset \" : \"\";\n return `${insetStr}${shadow.offsetX} ${shadow.offsetY} ${shadow.blurRadius} ${shadow.spreadRadius} ${shadow.color}`;\n}\n\n/**\n * Minify CSS by removing extra whitespace\n */\nfunction minifyCSS(css: string): string {\n return css\n .replace(/\\s+/g, \" \")\n .replace(/\\s*{\\s*/g, \"{\")\n .replace(/\\s*}\\s*/g, \"}\")\n .replace(/\\s*:\\s*/g, \":\")\n .replace(/\\s*;\\s*/g, \";\")\n .replace(/;\\s*}/g, \"}\")\n .trim();\n}\n\n/**\n * Check if a section has nested sections (is a container section)\n */\nexport function isContainerSection(\n section: FooterSection | FooterContentSection,\n): section is FooterSection {\n return \"sections\" in section && Array.isArray(section.sections);\n}\n\n/**\n * Check if a section is a content section (has items)\n */\nexport function isContentSection(\n section: FooterSection | FooterContentSection,\n): section is FooterContentSection {\n return \"items\" in section && Array.isArray(section.items);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/lib/footer.utils.ts"],"sourcesContent":["import {\n BorderConfig,\n FooterConfig,\n FooterContentSection,\n FooterSection,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { isResponsiveConfig } from \"@otl-core/cms-utils\";\nimport { resolveColorToCSS } from \"@otl-core/style-utils\";\n\n/**\n * Resolve all colors in the footer configuration to CSS values\n */\nexport function resolveFooterColors(\n style: FooterConfig[\"style\"],\n): Record<string, string | undefined> {\n const resolved: Record<string, string | undefined> = {\n background: resolveColorToCSS(style.background),\n text: resolveColorToCSS(style.text),\n linkColor: resolveColorToCSS(style.link.color),\n linkHoverColor: resolveColorToCSS(style.link.hoverColor),\n };\n\n return resolved;\n}\n\n/**\n * Resolve a responsive value to get the base value\n */\nfunction getResponsiveBase<T>(value: ResponsiveValue<T> | T): T {\n if (typeof value === \"object\" && value !== null && \"base\" in value) {\n return value.base;\n }\n return value as T;\n}\n\n/**\n * Resolve border config to CSS property string(s).\n * When width is a single value (e.g. \"1px\"), returns a `border` shorthand.\n * When width has multiple values (e.g. \"1px 0 0 0\"), returns separate properties.\n */\nfunction resolveBorder(\n border: ResponsiveValue<BorderConfig> | undefined,\n): string {\n if (!border) return \"\";\n\n const base = getResponsiveBase(border);\n if (!base) return \"\";\n\n const width = base.width ?? \"0\";\n const style = base.style ?? \"solid\";\n const color = base.color ? resolveColorToCSS(base.color) : \"transparent\";\n\n // Multi-value width (e.g. \"1px 0 0 0\") can't use border shorthand\n if (width.trim().includes(\" \")) {\n return `border-width: ${width}; border-style: ${style}; border-color: ${color}`;\n }\n\n return `border: ${width} ${style} ${color}`;\n}\n\n/**\n * Generate CSS for the footer configuration\n */\nexport function generateFooterCSS(\n id: string,\n footer: FooterConfig,\n resolvedColors: Record<string, string | undefined>,\n): string {\n const cssBlocks: string[] = [];\n\n // Base footer styles\n const baseMargin = getResponsiveBase(footer.style.layout.margin);\n const basePadding = getResponsiveBase(footer.style.layout.padding);\n const baseSectionGap = getResponsiveBase(footer.style.layout.sectionGap);\n const borderCSS = resolveBorder(footer.style.border);\n\n const baseStyles = `\n .footer-${id} {\n ${resolvedColors.background ? `background-color: ${resolvedColors.background};` : \"\"}\n ${resolvedColors.text ? `color: ${resolvedColors.text};` : \"\"}\n ${baseMargin ? `margin: ${baseMargin};` : \"\"}\n ${basePadding ? `padding: ${basePadding};` : \"\"}\n ${borderCSS ? `${borderCSS};` : \"\"}\n ${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : \"\"}\n }\n `;\n cssBlocks.push(baseStyles);\n\n // Link styles\n if (resolvedColors.linkColor || resolvedColors.linkHoverColor) {\n cssBlocks.push(`\n .footer-${id} a {\n ${resolvedColors.linkColor ? `color: ${resolvedColors.linkColor};` : \"\"}\n text-decoration: none;\n transition: color 0.2s;\n }\n .footer-${id} a:hover {\n ${resolvedColors.linkHoverColor ? `color: ${resolvedColors.linkHoverColor};` : \"\"}\n }\n `);\n }\n\n // Section gap\n if (baseSectionGap) {\n cssBlocks.push(`\n .footer-${id} > .footer-section {\n gap: ${baseSectionGap};\n }\n `);\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\n/**\n * Format shadow config to CSS box-shadow value\n */\nfunction formatShadow(shadow: ShadowConfig): string {\n const insetStr = shadow.inset ? \"inset \" : \"\";\n return `${insetStr}${shadow.offsetX} ${shadow.offsetY} ${shadow.blurRadius} ${shadow.spreadRadius} ${shadow.color}`;\n}\n\n/**\n * Minify CSS by removing extra whitespace\n */\nfunction minifyCSS(css: string): string {\n return css\n .replace(/\\s+/g, \" \")\n .replace(/\\s*{\\s*/g, \"{\")\n .replace(/\\s*}\\s*/g, \"}\")\n .replace(/\\s*:\\s*/g, \":\")\n .replace(/\\s*;\\s*/g, \";\")\n .replace(/;\\s*}/g, \"}\")\n .trim();\n}\n\n/**\n * Check if a section has nested sections (is a container section)\n */\nexport function isContainerSection(\n section: FooterSection | FooterContentSection,\n): section is FooterSection {\n return \"sections\" in section && Array.isArray(section.sections);\n}\n\n/**\n * Check if a section is a content section (has items)\n */\nexport function isContentSection(\n section: FooterSection | FooterContentSection,\n): section is FooterContentSection {\n return \"items\" in section && Array.isArray(section.items);\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.37",
3
+ "version": "1.1.39",
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.37",
52
- "@otl-core/style-utils": "^1.1.37"
51
+ "@otl-core/cms-utils": "^1.1.39",
52
+ "@otl-core/style-utils": "^1.1.39"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@eslint/eslintrc": "^3.3.1",
56
- "@otl-core/cms-types": "^1.1.37",
57
- "@otl-core/cms-utils": "^1.1.37",
56
+ "@otl-core/cms-types": "^1.1.39",
57
+ "@otl-core/cms-utils": "^1.1.39",
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",