brand-shell 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/default.css CHANGED
@@ -446,6 +446,8 @@
446
446
  .brand-shell-footer__name {
447
447
  font-size: 1rem;
448
448
  font-weight: 600;
449
+ color: var(--_text);
450
+ text-decoration: none;
449
451
  margin: 0 0 var(--brand-space-sm) 0;
450
452
  }
451
453
 
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as normalizeBrandTheme, c as themeToCssVariables, d as buildShellViewModelFromNormalized, f as normalizeBrandDetails, g as detailsToSocialLinks, h as normalizeNavLinks, i as formatValidationErrors, l as shouldValidateInDev, m as normalizeEmailHref, n as assertValidBrandDetails, o as validateBrandDetails, p as normalizeCtaLinks, r as assertValidBrandTheme, s as validateBrandTheme, t as BrandShellValidationError, u as buildShellViewModel } from "./validation-D5bzM9TH.mjs";
1
+ import { a as normalizeBrandTheme, c as themeToCssVariables, d as buildShellViewModelFromNormalized, f as normalizeBrandDetails, g as detailsToSocialLinks, h as normalizeNavLinks, i as formatValidationErrors, l as shouldValidateInDev, m as normalizeEmailHref, n as assertValidBrandDetails, o as validateBrandDetails, p as normalizeCtaLinks, r as assertValidBrandTheme, s as validateBrandTheme, t as BrandShellValidationError, u as buildShellViewModel } from "./validation-BhhgC3n1.mjs";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
 
4
4
  //#region src/react/theme.ts
@@ -239,14 +239,24 @@ function Footer({ details, theme, className, renderLink }) {
239
239
  children: [
240
240
  /* @__PURE__ */ jsxs("div", {
241
241
  className: "brand-shell-footer__brand",
242
- children: [normalizedDetails.logoSrc ? /* @__PURE__ */ jsx("img", {
243
- src: normalizedDetails.logoSrc,
244
- alt: normalizedDetails.logoAlt ?? normalizedDetails.name,
245
- className: "brand-shell-footer__logo"
246
- }) : /* @__PURE__ */ jsx("p", {
247
- className: "brand-shell-footer__name",
248
- children: normalizedDetails.name
249
- }), normalizedDetails.tagline && /* @__PURE__ */ jsx("p", {
242
+ children: [(() => {
243
+ const logoContent = normalizedDetails.logoSrc ? /* @__PURE__ */ jsx("img", {
244
+ src: normalizedDetails.logoSrc,
245
+ alt: normalizedDetails.logoAlt ?? normalizedDetails.name,
246
+ className: "brand-shell-footer__logo"
247
+ }) : null;
248
+ if (normalizedDetails.homeHref) return /* @__PURE__ */ jsx(LinkEl, {
249
+ href: normalizedDetails.homeHref,
250
+ className: "brand-shell-footer__name",
251
+ "aria-label": `${normalizedDetails.name} home`,
252
+ target: "_self",
253
+ children: logoContent ?? normalizedDetails.name
254
+ });
255
+ return logoContent ? logoContent : /* @__PURE__ */ jsx("p", {
256
+ className: "brand-shell-footer__name",
257
+ children: normalizedDetails.name
258
+ });
259
+ })(), normalizedDetails.tagline && /* @__PURE__ */ jsx("p", {
250
260
  className: "brand-shell-footer__tagline",
251
261
  children: normalizedDetails.tagline
252
262
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["SOCIAL_ICON_COMPONENTS"],"sources":["../src/react/theme.ts","../src/icons.tsx","../src/Header.tsx","../src/Footer.tsx"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport type { BrandTheme } from \"../core/types\";\nimport { themeToCssVariables } from \"../core/theme\";\n\nexport function themeToStyle(theme?: BrandTheme | null): CSSProperties {\n return themeToCssVariables(theme) as CSSProperties;\n}\n","/**\n * Social Media Icons\n *\n * Brand icons from lucide-react are deprecated and will be removed in v1.0.\n * This file provides reusable icon components using Simple Icons SVG paths.\n * See: https://github.com/lucide-icons/lucide/issues/670\n */\n\nimport type { SVGProps } from \"react\";\n\nexport interface IconProps extends SVGProps<SVGSVGElement> {\n className?: string;\n \"aria-label\"?: string;\n}\n\nexport function GithubIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n );\n}\n\nexport function TwitterIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\" />\n </svg>\n );\n}\n\nexport function LinkedinIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\" />\n </svg>\n );\n}\n\nexport function DiscordIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z\" />\n </svg>\n );\n}\n\nexport function MailIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\" />\n </svg>\n );\n}\n\nexport function GlobeIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\" />\n <path d=\"M2 12h20\" />\n </svg>\n );\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModelFromNormalized,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n GlobeIcon,\n LinkedinIcon,\n MailIcon,\n TwitterIcon,\n} from \"./icons\";\n\nexport interface LinkRenderProps {\n href: string;\n className: string;\n \"aria-label\": string;\n target: string;\n rel?: string;\n children: ReactNode;\n}\n\nexport interface HeaderProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n renderLink?: (props: LinkRenderProps) => ReactElement;\n}\n\nexport function Header({ details, theme, className, renderLink }: HeaderProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Header details\");\n assertValidBrandTheme(theme, \"brand-shell/Header theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);\n const combinedClassName = [\"brand-shell-header\", className].filter(Boolean).join(\" \");\n\n const LinkEl = renderLink\n ? renderLink\n : ({ href, className: cls, \"aria-label\": ariaLabel, target, rel, children }: LinkRenderProps) => (\n <a href={href} className={cls} aria-label={ariaLabel} target={target} rel={rel}>{children}</a>\n );\n\n const logoContent = normalizedDetails.logoSrc ? (\n <img\n src={normalizedDetails.logoSrc}\n alt={normalizedDetails.logoAlt ?? normalizedDetails.name}\n className=\"brand-shell-header__logo\"\n />\n ) : (\n normalizedDetails.name\n );\n\n const brandIdentity = normalizedDetails.homeHref ? (\n <LinkEl\n href={normalizedDetails.homeHref}\n className=\"brand-shell-header__name\"\n aria-label={`${normalizedDetails.name} home`}\n target=\"_self\"\n >\n {logoContent}\n </LinkEl>\n ) : (\n <span className=\"brand-shell-header__name\">{logoContent}</span>\n );\n\n return (\n <header className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"banner\">\n <div className=\"brand-shell-header__inner\">\n {brandIdentity}\n <div className=\"brand-shell-header__actions\">\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-header__nav\" aria-label=\"Primary\">\n <ul className=\"brand-shell-header__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <LinkEl\n href={link.href}\n className=\"brand-shell-header__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </LinkEl>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-header__ctas\">\n {ctaLinks.map((action) => (\n <LinkEl\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </LinkEl>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-header__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform as SocialPlatform];\n const isMailto = link.href.startsWith(\"mailto:\");\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-header__social-link\"\n aria-label={link.label}\n {...(!isMailto && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n >\n {Icon ? (\n <Icon aria-hidden=\"true\" />\n ) : link.iconSvg ? (\n <span dangerouslySetInnerHTML={{ __html: link.iconSvg }} aria-hidden=\"true\" />\n ) : (\n <span>{link.label[0]}</span>\n )}\n </a>\n );\n })}\n </div>\n )}\n </div>\n </div>\n </header>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: GlobeIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n","import type { ReactElement } from \"react\";\nimport type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModelFromNormalized,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n GlobeIcon,\n LinkedinIcon,\n MailIcon,\n TwitterIcon,\n} from \"./icons\";\n\nimport type { LinkRenderProps } from \"./Header\";\n\nexport interface FooterProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n renderLink?: (props: LinkRenderProps) => ReactElement;\n}\n\nexport function Footer({ details, theme, className, renderLink }: FooterProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Footer details\");\n assertValidBrandTheme(theme, \"brand-shell/Footer theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);\n const combinedClassName = [\"brand-shell-footer\", className].filter(Boolean).join(\" \");\n\n const LinkEl = renderLink\n ? renderLink\n : ({ href, className: cls, \"aria-label\": ariaLabel, target, rel, children }: LinkRenderProps) => (\n <a href={href} className={cls} aria-label={ariaLabel} target={target} rel={rel}>{children}</a>\n );\n\n return (\n <footer className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"contentinfo\">\n <div className=\"brand-shell-footer__inner\">\n <div className=\"brand-shell-footer__top\">\n <div className=\"brand-shell-footer__brand\">\n {normalizedDetails.logoSrc ? (\n <img\n src={normalizedDetails.logoSrc}\n alt={normalizedDetails.logoAlt ?? normalizedDetails.name}\n className=\"brand-shell-footer__logo\"\n />\n ) : (\n <p className=\"brand-shell-footer__name\">{normalizedDetails.name}</p>\n )}\n {normalizedDetails.tagline && <p className=\"brand-shell-footer__tagline\">{normalizedDetails.tagline}</p>}\n </div>\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-footer__nav\" aria-label=\"Footer\">\n <ul className=\"brand-shell-footer__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <LinkEl\n href={link.href}\n className=\"brand-shell-footer__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </LinkEl>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-footer__ctas\">\n {ctaLinks.map((action) => (\n <LinkEl\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </LinkEl>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-footer__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform as SocialPlatform];\n const isMailto = link.href.startsWith(\"mailto:\");\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-footer__social-link\"\n aria-label={link.label}\n {...(!isMailto && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n >\n {Icon ? (\n <Icon aria-hidden=\"true\" />\n ) : link.iconSvg ? (\n <span dangerouslySetInnerHTML={{ __html: link.iconSvg }} aria-hidden=\"true\" />\n ) : (\n <span>{link.label[0]}</span>\n )}\n </a>\n );\n })}\n </div>\n )}\n </div>\n <p className=\"brand-shell-footer__copy\">&copy; {new Date().getFullYear()} {normalizedDetails.name}</p>\n </div>\n </footer>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: GlobeIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["SOCIAL_ICON_COMPONENTS"],"sources":["../src/react/theme.ts","../src/icons.tsx","../src/Header.tsx","../src/Footer.tsx"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport type { BrandTheme } from \"../core/types\";\nimport { themeToCssVariables } from \"../core/theme\";\n\nexport function themeToStyle(theme?: BrandTheme | null): CSSProperties {\n return themeToCssVariables(theme) as CSSProperties;\n}\n","/**\n * Social Media Icons\n *\n * Brand icons from lucide-react are deprecated and will be removed in v1.0.\n * This file provides reusable icon components using Simple Icons SVG paths.\n * See: https://github.com/lucide-icons/lucide/issues/670\n */\n\nimport type { SVGProps } from \"react\";\n\nexport interface IconProps extends SVGProps<SVGSVGElement> {\n className?: string;\n \"aria-label\"?: string;\n}\n\nexport function GithubIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n );\n}\n\nexport function TwitterIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\" />\n </svg>\n );\n}\n\nexport function LinkedinIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\" />\n </svg>\n );\n}\n\nexport function DiscordIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z\" />\n </svg>\n );\n}\n\nexport function MailIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\" />\n </svg>\n );\n}\n\nexport function GlobeIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\" />\n <path d=\"M2 12h20\" />\n </svg>\n );\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModelFromNormalized,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n GlobeIcon,\n LinkedinIcon,\n MailIcon,\n TwitterIcon,\n} from \"./icons\";\n\nexport interface LinkRenderProps {\n href: string;\n className: string;\n \"aria-label\": string;\n target: string;\n rel?: string;\n children: ReactNode;\n}\n\nexport interface HeaderProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n renderLink?: (props: LinkRenderProps) => ReactElement;\n}\n\nexport function Header({ details, theme, className, renderLink }: HeaderProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Header details\");\n assertValidBrandTheme(theme, \"brand-shell/Header theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);\n const combinedClassName = [\"brand-shell-header\", className].filter(Boolean).join(\" \");\n\n const LinkEl = renderLink\n ? renderLink\n : ({ href, className: cls, \"aria-label\": ariaLabel, target, rel, children }: LinkRenderProps) => (\n <a href={href} className={cls} aria-label={ariaLabel} target={target} rel={rel}>{children}</a>\n );\n\n const logoContent = normalizedDetails.logoSrc ? (\n <img\n src={normalizedDetails.logoSrc}\n alt={normalizedDetails.logoAlt ?? normalizedDetails.name}\n className=\"brand-shell-header__logo\"\n />\n ) : (\n normalizedDetails.name\n );\n\n const brandIdentity = normalizedDetails.homeHref ? (\n <LinkEl\n href={normalizedDetails.homeHref}\n className=\"brand-shell-header__name\"\n aria-label={`${normalizedDetails.name} home`}\n target=\"_self\"\n >\n {logoContent}\n </LinkEl>\n ) : (\n <span className=\"brand-shell-header__name\">{logoContent}</span>\n );\n\n return (\n <header className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"banner\">\n <div className=\"brand-shell-header__inner\">\n {brandIdentity}\n <div className=\"brand-shell-header__actions\">\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-header__nav\" aria-label=\"Primary\">\n <ul className=\"brand-shell-header__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <LinkEl\n href={link.href}\n className=\"brand-shell-header__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </LinkEl>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-header__ctas\">\n {ctaLinks.map((action) => (\n <LinkEl\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </LinkEl>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-header__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform as SocialPlatform];\n const isMailto = link.href.startsWith(\"mailto:\");\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-header__social-link\"\n aria-label={link.label}\n {...(!isMailto && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n >\n {Icon ? (\n <Icon aria-hidden=\"true\" />\n ) : link.iconSvg ? (\n <span dangerouslySetInnerHTML={{ __html: link.iconSvg }} aria-hidden=\"true\" />\n ) : (\n <span>{link.label[0]}</span>\n )}\n </a>\n );\n })}\n </div>\n )}\n </div>\n </div>\n </header>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: GlobeIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n","import type { ReactElement } from \"react\";\nimport type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModelFromNormalized,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n GlobeIcon,\n LinkedinIcon,\n MailIcon,\n TwitterIcon,\n} from \"./icons\";\n\nimport type { LinkRenderProps } from \"./Header\";\n\nexport interface FooterProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n renderLink?: (props: LinkRenderProps) => ReactElement;\n}\n\nexport function Footer({ details, theme, className, renderLink }: FooterProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Footer details\");\n assertValidBrandTheme(theme, \"brand-shell/Footer theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);\n const combinedClassName = [\"brand-shell-footer\", className].filter(Boolean).join(\" \");\n\n const LinkEl = renderLink\n ? renderLink\n : ({ href, className: cls, \"aria-label\": ariaLabel, target, rel, children }: LinkRenderProps) => (\n <a href={href} className={cls} aria-label={ariaLabel} target={target} rel={rel}>{children}</a>\n );\n\n return (\n <footer className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"contentinfo\">\n <div className=\"brand-shell-footer__inner\">\n <div className=\"brand-shell-footer__top\">\n <div className=\"brand-shell-footer__brand\">\n {(() => {\n const logoContent = normalizedDetails.logoSrc ? (\n <img\n src={normalizedDetails.logoSrc}\n alt={normalizedDetails.logoAlt ?? normalizedDetails.name}\n className=\"brand-shell-footer__logo\"\n />\n ) : null;\n\n if (normalizedDetails.homeHref) {\n return (\n <LinkEl\n href={normalizedDetails.homeHref}\n className=\"brand-shell-footer__name\"\n aria-label={`${normalizedDetails.name} home`}\n target=\"_self\"\n >\n {logoContent ?? normalizedDetails.name}\n </LinkEl>\n );\n }\n\n return logoContent\n ? logoContent\n : <p className=\"brand-shell-footer__name\">{normalizedDetails.name}</p>;\n })()}\n {normalizedDetails.tagline && <p className=\"brand-shell-footer__tagline\">{normalizedDetails.tagline}</p>}\n </div>\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-footer__nav\" aria-label=\"Footer\">\n <ul className=\"brand-shell-footer__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <LinkEl\n href={link.href}\n className=\"brand-shell-footer__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </LinkEl>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-footer__ctas\">\n {ctaLinks.map((action) => (\n <LinkEl\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </LinkEl>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-footer__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform as SocialPlatform];\n const isMailto = link.href.startsWith(\"mailto:\");\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-footer__social-link\"\n aria-label={link.label}\n {...(!isMailto && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n >\n {Icon ? (\n <Icon aria-hidden=\"true\" />\n ) : link.iconSvg ? (\n <span dangerouslySetInnerHTML={{ __html: link.iconSvg }} aria-hidden=\"true\" />\n ) : (\n <span>{link.label[0]}</span>\n )}\n </a>\n );\n })}\n </div>\n )}\n </div>\n <p className=\"brand-shell-footer__copy\">&copy; {new Date().getFullYear()} {normalizedDetails.name}</p>\n </div>\n </footer>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: GlobeIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n"],"mappings":";;;;AAIA,SAAgB,aAAa,OAA0C;AACrE,QAAO,oBAAoB,MAAM;;;;;ACUnC,SAAgB,WAAW,EAAE,WAAW,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAoB;AAC5F,QACE,oBAAC;EAAI,SAAQ;EAAY,MAAK;EAA0B;EAAkB;EAAe;EAAQ,GAAI;YACnG,oBAAC,UAAK,GAAE,8sBAA8sB;GACltB;;AAIV,SAAgB,YAAY,EAAE,WAAW,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAoB;AAC7F,QACE,oBAAC;EAAI,SAAQ;EAAY,MAAK;EAA0B;EAAkB;EAAe;EAAQ,GAAI;YACnG,oBAAC,UAAK,GAAE,gKAAgK;GACpK;;AAIV,SAAgB,aAAa,EAAE,WAAW,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAoB;AAC9F,QACE,oBAAC;EAAI,SAAQ;EAAY,MAAK;EAA0B;EAAkB;EAAe;EAAQ,GAAI;YACnG,oBAAC,UAAK,GAAE,ufAAuf;GAC3f;;AAIV,SAAgB,YAAY,EAAE,WAAW,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAoB;AAC7F,QACE,oBAAC;EAAI,SAAQ;EAAY,MAAK;EAA0B;EAAkB;EAAe;EAAQ,GAAI;YACnG,oBAAC,UAAK,GAAE,+jCAA+jC;GACnkC;;AAIV,SAAgB,SAAS,EAAE,WAAW,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAoB;AAC1F,QACE,qBAAC;EACC,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAY;EACZ,eAAc;EACd,gBAAe;EACJ;EACJ;EACC;EACR,GAAI;aAEJ,oBAAC;GAAK,OAAM;GAAK,QAAO;GAAK,GAAE;GAAI,GAAE;GAAI,IAAG;IAAM,EAClD,oBAAC,UAAK,GAAE,8CAA8C;GAClD;;AAIV,SAAgB,UAAU,EAAE,WAAW,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAoB;AAC3F,QACE,qBAAC;EACC,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAY;EACZ,eAAc;EACd,gBAAe;EACJ;EACJ;EACC;EACR,GAAI;;GAEJ,oBAAC;IAAO,IAAG;IAAK,IAAG;IAAK,GAAE;KAAO;GACjC,oBAAC,UAAK,GAAE,oDAAoD;GAC5D,oBAAC,UAAK,GAAE,aAAa;;GACjB;;;;;AC9CV,SAAgB,OAAO,EAAE,SAAS,OAAO,WAAW,cAA2B;AAC7E,KAAI,qBAAqB,EAAE;AACzB,0BAAwB,SAAS,6BAA6B;AAC9D,wBAAsB,OAAO,2BAA2B;;CAG1D,MAAM,oBAAoB,sBAAsB,QAAQ;CACxD,MAAM,kBAAkB,oBAAoB,MAAM;CAClD,MAAM,YAAY,iBAAiB,cAAc,YAAY,YAAY;CACzE,MAAM,QAAQ,aAAa,gBAAgB;CAC3C,MAAM,EAAE,UAAU,UAAU,gBAAgB,kCAAkC,kBAAkB;CAChG,MAAM,oBAAoB,CAAC,sBAAsB,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;CAErF,MAAM,SAAS,aACX,cACC,EAAE,MAAM,WAAW,KAAK,cAAc,WAAW,QAAQ,KAAK,eAC7D,oBAAC;EAAQ;EAAM,WAAW;EAAK,cAAY;EAAmB;EAAa;EAAM;GAAa;CAGpG,MAAM,cAAc,kBAAkB,UACpC,oBAAC;EACC,KAAK,kBAAkB;EACvB,KAAK,kBAAkB,WAAW,kBAAkB;EACpD,WAAU;GACV,GAEF,kBAAkB;CAGpB,MAAM,gBAAgB,kBAAkB,WACtC,oBAAC;EACC,MAAM,kBAAkB;EACxB,WAAU;EACV,cAAY,GAAG,kBAAkB,KAAK;EACtC,QAAO;YAEN;GACM,GAET,oBAAC;EAAK,WAAU;YAA4B;GAAmB;AAGjE,QACE,oBAAC;EAAO,WAAW;EAAmB,yBAAuB;EAAkB;EAAO,MAAK;YACzF,qBAAC;GAAI,WAAU;cACZ,eACD,qBAAC;IAAI,WAAU;;KACZ,SAAS,SAAS,KACjB,oBAAC;MAAI,WAAU;MAA0B,cAAW;gBAClD,oBAAC;OAAG,WAAU;iBACX,SAAS,KAAK,SAAS;AACtB,eACE,oBAAC,kBACC,oBAAC;SACC,MAAM,KAAK;SACX,WAAU;SACV,cAAY,KAAK;SACjB,QAAQ,KAAK;SACb,KAAK,KAAK;mBAET,KAAK;UACC,IATF,KAAK,OAAO,KAAK,MAUrB;SAEP;QACC;OACD;KAEP,SAAS,SAAS,KACjB,oBAAC;MAAI,WAAU;gBACZ,SAAS,KAAK,WACb,oBAAC;OAEC,MAAM,OAAO;OACb,WAAW,CAAC,sBAAsB,uBAAuB,OAAO,UAAU,CAAC,KAAK,IAAI;OACpF,cAAY,OAAO;OACnB,QAAQ,OAAO;OACf,KAAK,OAAO;iBAEX,OAAO;SAPH,OAAO,OAAO,OAAO,MAQnB,CACT;OACE;KAEP,YAAY,SAAS,KACpB,oBAAC;MAAI,WAAU;MAA6B,cAAW;gBACpD,YAAY,KAAK,SAAS;OACzB,MAAM,OAAOA,yBAAuB,KAAK;OACzC,MAAM,WAAW,KAAK,KAAK,WAAW,UAAU;AAChD,cACE,oBAAC;QAEC,MAAM,KAAK;QACX,WAAU;QACV,cAAY,KAAK;QACjB,GAAK,CAAC,YAAY;SAAE,QAAQ;SAAU,KAAK;SAAuB;kBAEjE,OACC,oBAAC,QAAK,eAAY,SAAS,GACzB,KAAK,UACP,oBAAC;SAAK,yBAAyB,EAAE,QAAQ,KAAK,SAAS;SAAE,eAAY;UAAS,GAE9E,oBAAC,oBAAM,KAAK,MAAM,KAAU;UAXzB,KAAK,OAAO,KAAK,SAapB;QAEN;OACE;;KAEJ;IACF;GACC;;AAIb,MAAMA,2BAAoF;CACxF,SAAS;CACT,UAAU;CACV,OAAO;CACP,QAAQ;CACR,SAAS;CACT,SAAS;CACV;;;;ACjID,SAAgB,OAAO,EAAE,SAAS,OAAO,WAAW,cAA2B;AAC7E,KAAI,qBAAqB,EAAE;AACzB,0BAAwB,SAAS,6BAA6B;AAC9D,wBAAsB,OAAO,2BAA2B;;CAG1D,MAAM,oBAAoB,sBAAsB,QAAQ;CACxD,MAAM,kBAAkB,oBAAoB,MAAM;CAClD,MAAM,YAAY,iBAAiB,cAAc,YAAY,YAAY;CACzE,MAAM,QAAQ,aAAa,gBAAgB;CAC3C,MAAM,EAAE,UAAU,UAAU,gBAAgB,kCAAkC,kBAAkB;CAChG,MAAM,oBAAoB,CAAC,sBAAsB,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;CAErF,MAAM,SAAS,aACX,cACC,EAAE,MAAM,WAAW,KAAK,cAAc,WAAW,QAAQ,KAAK,eAC7D,oBAAC;EAAQ;EAAM,WAAW;EAAK,cAAY;EAAmB;EAAa;EAAM;GAAa;AAGpG,QACE,oBAAC;EAAO,WAAW;EAAmB,yBAAuB;EAAkB;EAAO,MAAK;YACzF,qBAAC;GAAI,WAAU;cACb,qBAAC;IAAI,WAAU;;KACb,qBAAC;MAAI,WAAU;wBACL;OACN,MAAM,cAAc,kBAAkB,UACpC,oBAAC;QACC,KAAK,kBAAkB;QACvB,KAAK,kBAAkB,WAAW,kBAAkB;QACpD,WAAU;SACV,GACA;AAEJ,WAAI,kBAAkB,SACpB,QACE,oBAAC;QACC,MAAM,kBAAkB;QACxB,WAAU;QACV,cAAY,GAAG,kBAAkB,KAAK;QACtC,QAAO;kBAEN,eAAe,kBAAkB;SAC3B;AAIb,cAAO,cACH,cACA,oBAAC;QAAE,WAAU;kBAA4B,kBAAkB;SAAS;UACtE,EACH,kBAAkB,WAAW,oBAAC;OAAE,WAAU;iBAA+B,kBAAkB;QAAY;OACpG;KACL,SAAS,SAAS,KACjB,oBAAC;MAAI,WAAU;MAA0B,cAAW;gBAClD,oBAAC;OAAG,WAAU;iBACX,SAAS,KAAK,SAAS;AACtB,eACE,oBAAC,kBACC,oBAAC;SACC,MAAM,KAAK;SACX,WAAU;SACV,cAAY,KAAK;SACjB,QAAQ,KAAK;SACb,KAAK,KAAK;mBAET,KAAK;UACC,IATF,KAAK,OAAO,KAAK,MAUrB;SAEP;QACC;OACD;KAEP,SAAS,SAAS,KACjB,oBAAC;MAAI,WAAU;gBACZ,SAAS,KAAK,WACb,oBAAC;OAEC,MAAM,OAAO;OACb,WAAW,CAAC,sBAAsB,uBAAuB,OAAO,UAAU,CAAC,KAAK,IAAI;OACpF,cAAY,OAAO;OACnB,QAAQ,OAAO;OACf,KAAK,OAAO;iBAEX,OAAO;SAPH,OAAO,OAAO,OAAO,MAQnB,CACT;OACE;KAEP,YAAY,SAAS,KACpB,oBAAC;MAAI,WAAU;MAA6B,cAAW;gBACpD,YAAY,KAAK,SAAS;OACzB,MAAM,OAAO,uBAAuB,KAAK;OACzC,MAAM,WAAW,KAAK,KAAK,WAAW,UAAU;AAChD,cACE,oBAAC;QAEC,MAAM,KAAK;QACX,WAAU;QACV,cAAY,KAAK;QACjB,GAAK,CAAC,YAAY;SAAE,QAAQ;SAAU,KAAK;SAAuB;kBAEjE,OACC,oBAAC,QAAK,eAAY,SAAS,GACzB,KAAK,UACP,oBAAC;SAAK,yBAAyB,EAAE,QAAQ,KAAK,SAAS;SAAE,eAAY;UAAS,GAE9E,oBAAC,oBAAM,KAAK,MAAM,KAAU;UAXzB,KAAK,OAAO,KAAK,SAapB;QAEN;OACE;;KAEJ,EACN,qBAAC;IAAE,WAAU;;KAA2B;sBAAQ,IAAI,MAAM,EAAC,aAAa;KAAC;KAAE,kBAAkB;;KAAS;IAClG;GACC;;AAIb,MAAM,yBAAoF;CACxF,SAAS;CACT,UAAU;CACV,OAAO;CACP,QAAQ;CACR,SAAS;CACT,SAAS;CACV"}
package/dist/svelte.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { l as shouldValidateInDev, n as assertValidBrandDetails, r as assertValidBrandTheme } from "./validation-D5bzM9TH.mjs";
1
+ import { l as shouldValidateInDev, n as assertValidBrandDetails, r as assertValidBrandTheme } from "./validation-BhhgC3n1.mjs";
2
2
  import { applyBrandShellProps, registerBrandShellElements } from "./web.mjs";
3
3
 
4
4
  //#region src/svelte/index.ts
@@ -60,6 +60,7 @@ function normalizeSafeHref(href) {
60
60
  const schemeMatch = trimmed.match(ABSOLUTE_SCHEME_PATTERN);
61
61
  if (!schemeMatch) return trimmed;
62
62
  const protocol = `${schemeMatch[1]?.toLowerCase()}:`;
63
+ if (protocol === "data:") return trimmed.startsWith("data:image/") ? trimmed : void 0;
63
64
  if (!ALLOWED_PROTOCOLS.has(protocol)) return;
64
65
  return trimmed;
65
66
  }
@@ -485,4 +486,4 @@ function isRecord(value) {
485
486
 
486
487
  //#endregion
487
488
  export { normalizeBrandTheme as a, themeToCssVariables as c, buildShellViewModelFromNormalized as d, normalizeBrandDetails as f, detailsToSocialLinks as g, normalizeNavLinks as h, formatValidationErrors as i, shouldValidateInDev as l, normalizeEmailHref as m, assertValidBrandDetails as n, validateBrandDetails as o, normalizeCtaLinks as p, assertValidBrandTheme as r, validateBrandTheme as s, BrandShellValidationError as t, buildShellViewModel as u };
488
- //# sourceMappingURL=validation-D5bzM9TH.mjs.map
489
+ //# sourceMappingURL=validation-BhhgC3n1.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-BhhgC3n1.mjs","names":[],"sources":["../src/core/social.ts","../src/core/links.ts","../src/core/shell.ts","../src/core/dev.ts","../src/core/theme.ts","../src/core/validation.ts"],"sourcesContent":["import type { BrandDetails } from \"./types\";\n\nexport type SocialPlatform = \"website\" | \"linkedin\" | \"email\" | \"github\" | \"twitter\" | \"discord\";\n\nexport interface SocialLink {\n platform: SocialPlatform | string;\n href: string;\n label: string;\n iconSvg?: string;\n}\n\nexport function detailsToSocialLinks(details: BrandDetails): SocialLink[] {\n const links: SocialLink[] = [];\n if (details.website) links.push({ platform: \"website\", href: details.website, label: \"Website\" });\n if (details.linkedin) links.push({ platform: \"linkedin\", href: details.linkedin, label: \"LinkedIn\" });\n if (details.email) links.push({ platform: \"email\", href: details.email, label: \"Email\" });\n if (details.github) links.push({ platform: \"github\", href: details.github, label: \"GitHub\" });\n if (details.twitter) links.push({ platform: \"twitter\", href: details.twitter, label: \"Twitter\" });\n if (details.discord) links.push({ platform: \"discord\", href: details.discord, label: \"Discord\" });\n if (details.customSocialLinks) {\n for (const custom of details.customSocialLinks) {\n links.push({ platform: custom.platform, href: custom.href, label: custom.label, iconSvg: custom.iconSvg });\n }\n }\n return links;\n}\n","const ABSOLUTE_SCHEME_PATTERN = /^([a-zA-Z][a-zA-Z\\d+.-]*):/;\nconst UNSAFE_CHAR_PATTERN = /[\\u0000-\\u001f\\u007f]/;\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\"]);\nconst REQUIRED_BLANK_REL_TOKENS = [\"noopener\", \"noreferrer\"];\n\nexport function normalizeSafeHref(href: unknown): string | undefined {\n if (typeof href !== \"string\") return undefined;\n const trimmed = href.trim();\n if (trimmed.length === 0) return undefined;\n if (UNSAFE_CHAR_PATTERN.test(trimmed)) return undefined;\n if (trimmed.startsWith(\"//\")) return undefined;\n\n const schemeMatch = trimmed.match(ABSOLUTE_SCHEME_PATTERN);\n if (!schemeMatch) {\n return trimmed;\n }\n\n const protocol = `${schemeMatch[1]?.toLowerCase()}:`;\n if (protocol === \"data:\") {\n return trimmed.startsWith(\"data:image/\") ? trimmed : undefined;\n }\n if (!ALLOWED_PROTOCOLS.has(protocol)) {\n return undefined;\n }\n\n return trimmed;\n}\n\nexport function isSafeHref(href: unknown): boolean {\n return normalizeSafeHref(href) != null;\n}\n\nexport function normalizeRel(target: \"_blank\" | \"_self\" | \"_parent\" | \"_top\", rel?: string): string | undefined {\n const normalizedRel = typeof rel === \"string\" ? rel.trim() : \"\";\n if (target !== \"_blank\") {\n return normalizedRel.length > 0 ? normalizedRel : undefined;\n }\n\n const tokens = normalizedRel.length > 0 ? normalizedRel.split(/\\s+/).filter(Boolean) : [];\n const tokenSet = new Set(tokens.map((token) => token.toLowerCase()));\n\n for (const requiredToken of REQUIRED_BLANK_REL_TOKENS) {\n if (!tokenSet.has(requiredToken)) {\n tokens.push(requiredToken);\n }\n }\n\n return tokens.join(\" \");\n}\n","import { detailsToSocialLinks, type SocialLink } from \"./social\";\nimport type { BrandAction, BrandDetails, BrandNavLink, CustomSocialLink } from \"./types\";\nimport { normalizeRel, normalizeSafeHref } from \"./links\";\n\nexport type LinkTarget = NonNullable<BrandNavLink[\"target\"]>;\n\nexport interface ShellNavLink extends BrandNavLink {\n ariaLabel: string;\n rel?: string;\n target: LinkTarget;\n}\n\nexport interface ShellActionLink extends BrandAction {\n ariaLabel: string;\n rel?: string;\n target: LinkTarget;\n variant: NonNullable<BrandAction[\"variant\"]>;\n}\n\nexport interface ShellViewModel {\n navLinks: ShellNavLink[];\n ctaLinks: ShellActionLink[];\n socialLinks: SocialLink[];\n}\n\nexport type NormalizedActionLink = Omit<ShellActionLink, \"variant\"> & Pick<BrandAction, \"variant\">;\n\nexport interface NormalizedBrandDetails extends Omit<BrandDetails, \"navLinks\" | \"primaryAction\" | \"secondaryAction\"> {\n navLinks: ShellNavLink[];\n primaryAction?: NormalizedActionLink;\n secondaryAction?: NormalizedActionLink;\n}\n\nexport function normalizeNavLinks(navLinks: BrandNavLink[] = []): ShellNavLink[] {\n return navLinks.flatMap((link) => {\n const href = normalizeSafeHref(link.href);\n if (!href) return [];\n\n const { target, rel } = normalizeLinkTargetRel(link.target, link.rel);\n return {\n ...link,\n href,\n ariaLabel: link.ariaLabel ?? link.label,\n target,\n rel,\n };\n });\n}\n\nexport function normalizeBrandDetails(details: BrandDetails): NormalizedBrandDetails {\n const normalizedPrimaryAction = normalizeAction(details.primaryAction);\n const normalizedSecondaryAction = normalizeAction(details.secondaryAction);\n\n return {\n ...details,\n homeHref: normalizeSafeHref(details.homeHref),\n email: normalizeEmailHref(details.email),\n website: normalizeSafeHref(details.website),\n linkedin: normalizeSafeHref(details.linkedin),\n github: normalizeSafeHref(details.github),\n twitter: normalizeSafeHref(details.twitter),\n discord: normalizeSafeHref(details.discord),\n navLinks: normalizeNavLinks(details.navLinks),\n primaryAction: normalizedPrimaryAction,\n secondaryAction: normalizedSecondaryAction,\n customSocialLinks: normalizeCustomSocialLinks(details.customSocialLinks),\n logoSrc: normalizeSafeHref(details.logoSrc),\n logoAlt: details.logoAlt,\n };\n}\n\nexport function normalizeCtaLinks(\n primaryAction?: BrandAction,\n secondaryAction?: BrandAction,\n): ShellActionLink[] {\n const normalizedPrimaryAction = normalizeAction(primaryAction);\n const normalizedSecondaryAction = normalizeAction(secondaryAction);\n const actions = [normalizedSecondaryAction, normalizedPrimaryAction].filter(\n (action): action is NonNullable<typeof action> => Boolean(action),\n );\n\n return actions.map((action, index) => {\n const variant =\n action.variant ?? (action === normalizedPrimaryAction || index === actions.length - 1 ? \"primary\" : \"secondary\");\n\n return {\n ...action,\n variant,\n };\n });\n}\n\nexport function buildShellViewModelFromNormalized(normalized: NormalizedBrandDetails): ShellViewModel {\n return {\n navLinks: normalized.navLinks,\n ctaLinks: normalizeCtaLinks(normalized.primaryAction, normalized.secondaryAction),\n socialLinks: detailsToSocialLinks(normalized),\n };\n}\n\nexport function buildShellViewModel(details: BrandDetails): ShellViewModel {\n return buildShellViewModelFromNormalized(normalizeBrandDetails(details));\n}\n\nexport function normalizeEmailHref(email?: string): string | undefined {\n if (typeof email !== \"string\") return undefined;\n const trimmed = email.trim();\n if (trimmed.length === 0) return undefined;\n if (trimmed.toLowerCase().startsWith(\"mailto:\")) {\n const address = trimmed.slice(7).trim();\n if (address.length === 0) return undefined;\n return normalizeSafeHref(`mailto:${address}`);\n }\n return normalizeSafeHref(`mailto:${trimmed}`);\n}\n\nfunction normalizeCustomSocialLinks(links?: CustomSocialLink[]): CustomSocialLink[] | undefined {\n if (!links || links.length === 0) return undefined;\n const normalized: CustomSocialLink[] = [];\n for (const link of links) {\n const href = normalizeSafeHref(link.href);\n if (!href) continue;\n normalized.push({ ...link, href });\n }\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction normalizeAction(action?: BrandAction): NormalizedActionLink | undefined {\n if (!action) return undefined;\n\n const href = normalizeSafeHref(action.href);\n if (!href) return undefined;\n\n const { target, rel } = normalizeLinkTargetRel(action.target, action.rel);\n return {\n ...action,\n href,\n target,\n rel,\n ariaLabel: action.ariaLabel ?? action.label,\n };\n}\n\nexport function normalizeLinkTargetRel(target?: BrandNavLink[\"target\"], rel?: string) {\n const normalizedTarget: LinkTarget = target ?? \"_self\";\n const normalizedRel = normalizeRel(normalizedTarget, rel);\n return {\n target: normalizedTarget,\n rel: normalizedRel,\n };\n}\n","type ImportMetaEnv = {\n DEV?: boolean;\n MODE?: string;\n};\n\ntype ImportMetaLike = {\n env?: ImportMetaEnv;\n};\n\nexport function shouldValidateInDev(): boolean {\n const nodeEnv = typeof process !== \"undefined\" ? process.env?.NODE_ENV : undefined;\n if (typeof nodeEnv === \"string\") {\n return nodeEnv !== \"production\";\n }\n\n const { env } = import.meta as unknown as ImportMetaLike;\n if (typeof env?.DEV === \"boolean\") {\n return env.DEV;\n }\n\n return false;\n}\n","import type { BrandTheme } from \"./types\";\n\nconst THEME_VAR_PREFIX = \"brand\";\nconst DARK_TEXT = \"#0f172a\";\nconst LIGHT_TEXT = \"#f8fafc\";\n\nexport type ThemeVariables = Record<string, string>;\n\nexport function themeToCssVariables(theme?: BrandTheme | null): ThemeVariables {\n if (!theme) return {};\n const style: ThemeVariables = {};\n if (theme.primaryColor != null) style[`--${THEME_VAR_PREFIX}-primary`] = theme.primaryColor;\n if (theme.backgroundColor != null) style[`--${THEME_VAR_PREFIX}-bg`] = theme.backgroundColor;\n if (theme.textColor != null) style[`--${THEME_VAR_PREFIX}-text`] = theme.textColor;\n if (theme.fontFamily != null) style[`--${THEME_VAR_PREFIX}-font`] = theme.fontFamily;\n if (theme.linkColor != null) style[`--${THEME_VAR_PREFIX}-link`] = theme.linkColor;\n if (theme.socialIconSize != null) style[`--${THEME_VAR_PREFIX}-social-size`] = theme.socialIconSize;\n if (theme.buttonTextColor != null) {\n style[`--${THEME_VAR_PREFIX}-button-text`] = theme.buttonTextColor;\n } else if (theme.primaryColor != null) {\n const buttonTextColor = getAccessibleTextColor(theme.primaryColor);\n if (buttonTextColor) style[`--${THEME_VAR_PREFIX}-button-text`] = buttonTextColor;\n }\n if (theme.borderRadius != null) style[`--${THEME_VAR_PREFIX}-radius`] = theme.borderRadius;\n if (theme.headerHeight != null) style[`--${THEME_VAR_PREFIX}-header-height`] = theme.headerHeight;\n if (theme.footerPadding != null) style[`--${THEME_VAR_PREFIX}-footer-padding`] = theme.footerPadding;\n if (theme.secondaryButtonBg != null) style[`--${THEME_VAR_PREFIX}-button-secondary`] = theme.secondaryButtonBg;\n if (theme.logoHeight != null) style[`--${THEME_VAR_PREFIX}-logo-height`] = theme.logoHeight;\n return style;\n}\n\nfunction getAccessibleTextColor(backgroundColor: string): string | undefined {\n const rgb = parseColorToRgb(backgroundColor);\n if (!rgb) return undefined;\n\n const contrastWithDark = contrastRatio(rgb, { r: 15, g: 23, b: 42 });\n const contrastWithLight = contrastRatio(rgb, { r: 248, g: 250, b: 252 });\n\n return contrastWithDark > contrastWithLight ? DARK_TEXT : LIGHT_TEXT;\n}\n\n/**\n * Parses a hex (#rgb / #rrggbb) or rgb()/rgba() color string to RGB components.\n * hsl(), oklch(), and other formats are not supported and return undefined.\n */\nfunction parseColorToRgb(color: string): { r: number; g: number; b: number } | undefined {\n const trimmed = color.trim();\n\n const hexMatch = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(trimmed);\n if (hexMatch) {\n const value = hexMatch[1];\n if (value.length === 3) {\n return {\n r: Number.parseInt(value[0] + value[0], 16),\n g: Number.parseInt(value[1] + value[1], 16),\n b: Number.parseInt(value[2] + value[2], 16),\n };\n }\n return {\n r: Number.parseInt(value.slice(0, 2), 16),\n g: Number.parseInt(value.slice(2, 4), 16),\n b: Number.parseInt(value.slice(4, 6), 16),\n };\n }\n\n const rgbMatch = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/.exec(trimmed);\n if (rgbMatch) {\n return { r: +rgbMatch[1], g: +rgbMatch[2], b: +rgbMatch[3] };\n }\n\n return undefined;\n}\n\nfunction contrastRatio(\n first: { r: number; g: number; b: number },\n second: { r: number; g: number; b: number },\n): number {\n const firstLuminance = relativeLuminance(first);\n const secondLuminance = relativeLuminance(second);\n const lighter = Math.max(firstLuminance, secondLuminance);\n const darker = Math.min(firstLuminance, secondLuminance);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction relativeLuminance(color: { r: number; g: number; b: number }): number {\n const transform = (channel: number) => {\n const normalized = channel / 255;\n if (normalized <= 0.03928) return normalized / 12.92;\n return ((normalized + 0.055) / 1.055) ** 2.4;\n };\n\n const r = transform(color.r);\n const g = transform(color.g);\n const b = transform(color.b);\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n","import { normalizeBrandDetails, normalizeEmailHref, type NormalizedBrandDetails } from \"./shell\";\nimport { normalizeSafeHref } from \"./links\";\nimport type { BrandAction, BrandDetails, BrandNavLink, BrandTheme, CustomSocialLink } from \"./types\";\n\nconst LINK_TARGETS = new Set<NonNullable<BrandNavLink[\"target\"]>>([\"_blank\", \"_self\", \"_parent\", \"_top\"]);\nconst CTA_VARIANTS = new Set<NonNullable<BrandAction[\"variant\"]>>([\"primary\", \"secondary\", \"ghost\"]);\nconst CTA_LAYOUTS = new Set<NonNullable<BrandTheme[\"ctaLayout\"]>>([\"inline\", \"stacked\"]);\nconst THEME_KEYS = new Set<keyof BrandTheme>([\n \"primaryColor\",\n \"backgroundColor\",\n \"textColor\",\n \"fontFamily\",\n \"linkColor\",\n \"socialIconSize\",\n \"buttonTextColor\",\n \"ctaLayout\",\n \"borderRadius\",\n \"headerHeight\",\n \"footerPadding\",\n \"secondaryButtonBg\",\n \"logoHeight\",\n]);\n\ntype ValidationErrorPath = string;\n\nexport interface BrandValidationResult<T> {\n valid: boolean;\n errors: string[];\n normalized: T | null;\n}\n\nexport class BrandShellValidationError extends Error {\n readonly context: string;\n readonly errors: string[];\n\n constructor(context: string, errors: string[]) {\n super(formatValidationErrors(context, errors));\n this.name = \"BrandShellValidationError\";\n this.context = context;\n this.errors = errors;\n }\n}\n\nexport function validateBrandDetails(details: unknown): BrandValidationResult<NormalizedBrandDetails> {\n const errors: string[] = [];\n\n if (!isRecord(details)) {\n errors.push(\"details must be an object.\");\n return { valid: false, errors, normalized: null };\n }\n\n validateRequiredString(details.name, \"details.name\", errors);\n validateOptionalString(details.homeHref, \"details.homeHref\", errors);\n validateSafeHref(details.homeHref, \"details.homeHref\", errors);\n validateOptionalString(details.website, \"details.website\", errors);\n validateSafeHref(details.website, \"details.website\", errors);\n validateOptionalString(details.linkedin, \"details.linkedin\", errors);\n validateSafeHref(details.linkedin, \"details.linkedin\", errors);\n validateOptionalString(details.email, \"details.email\", errors);\n validateEmail(details.email, \"details.email\", errors);\n validateOptionalString(details.github, \"details.github\", errors);\n validateSafeHref(details.github, \"details.github\", errors);\n validateOptionalString(details.twitter, \"details.twitter\", errors);\n validateSafeHref(details.twitter, \"details.twitter\", errors);\n validateOptionalString(details.discord, \"details.discord\", errors);\n validateSafeHref(details.discord, \"details.discord\", errors);\n validateOptionalString(details.tagline, \"details.tagline\", errors);\n validateOptionalString(details.logoSrc, \"details.logoSrc\", errors);\n validateSafeHref(details.logoSrc, \"details.logoSrc\", errors);\n validateOptionalString(details.logoAlt, \"details.logoAlt\", errors);\n\n if (details.navLinks != null) {\n if (!Array.isArray(details.navLinks)) {\n errors.push(\"details.navLinks must be an array.\");\n } else {\n details.navLinks.forEach((link, index) => validateNavLink(link, `details.navLinks[${index}]`, errors));\n }\n }\n\n if (details.primaryAction != null) {\n validateAction(details.primaryAction, \"details.primaryAction\", errors);\n }\n if (details.secondaryAction != null) {\n validateAction(details.secondaryAction, \"details.secondaryAction\", errors);\n }\n\n if (details.customSocialLinks != null) {\n if (!Array.isArray(details.customSocialLinks)) {\n errors.push(\"details.customSocialLinks must be an array.\");\n } else {\n details.customSocialLinks.forEach((link, index) =>\n validateCustomSocialLink(link, `details.customSocialLinks[${index}]`, errors),\n );\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors, normalized: null };\n }\n\n return {\n valid: true,\n errors: [],\n normalized: normalizeBrandDetails(details as unknown as BrandDetails),\n };\n}\n\nexport function validateBrandTheme(theme: unknown): BrandValidationResult<BrandTheme | null> {\n if (theme == null) {\n return {\n valid: true,\n errors: [],\n normalized: null,\n };\n }\n\n const errors: string[] = [];\n\n if (!isRecord(theme)) {\n errors.push(\"theme must be an object when provided.\");\n return { valid: false, errors, normalized: null };\n }\n\n for (const key of Object.keys(theme)) {\n if (!THEME_KEYS.has(key as keyof BrandTheme)) {\n errors.push(`theme.${key} is not a supported theme key.`);\n continue;\n }\n if (key === \"ctaLayout\") {\n validateCtaLayout(theme[key], \"theme.ctaLayout\", errors);\n continue;\n }\n validateOptionalString(theme[key], `theme.${key}`, errors);\n }\n\n if (errors.length > 0) {\n return { valid: false, errors, normalized: null };\n }\n\n return {\n valid: true,\n errors: [],\n normalized: normalizeBrandTheme(theme as BrandTheme),\n };\n}\n\nexport function assertValidBrandDetails(details: unknown, context = \"BrandDetails\"): asserts details is BrandDetails {\n const result = validateBrandDetails(details);\n if (!result.valid) {\n throw new BrandShellValidationError(context, result.errors);\n }\n}\n\nexport function assertValidBrandTheme(theme: unknown, context = \"BrandTheme\"): asserts theme is BrandTheme | null | undefined {\n const result = validateBrandTheme(theme);\n if (!result.valid) {\n throw new BrandShellValidationError(context, result.errors);\n }\n}\n\nexport function normalizeBrandTheme(theme?: BrandTheme | null): BrandTheme | null {\n if (!theme) return null;\n\n const normalized: BrandTheme = {};\n for (const key of THEME_KEYS) {\n const value = theme[key];\n if (key === \"ctaLayout\") {\n if (typeof value === \"string\" && CTA_LAYOUTS.has(value as NonNullable<BrandTheme[\"ctaLayout\"]>)) {\n normalized[key] = value as BrandTheme[\"ctaLayout\"];\n }\n continue;\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length > 0) {\n normalized[key] = trimmed;\n }\n }\n }\n\n return Object.keys(normalized).length > 0 ? normalized : null;\n}\n\nexport function formatValidationErrors(context: string, errors: string[]): string {\n return `${context} validation failed:\\n${errors.map((error) => `- ${error}`).join(\"\\n\")}`;\n}\n\nfunction validateNavLink(link: unknown, path: ValidationErrorPath, errors: string[]) {\n if (!isRecord(link)) {\n errors.push(`${path} must be an object.`);\n return;\n }\n\n validateRequiredString(link.label, `${path}.label`, errors);\n validateRequiredString(link.href, `${path}.href`, errors);\n validateSafeHref(link.href, `${path}.href`, errors);\n validateOptionalString(link.ariaLabel, `${path}.ariaLabel`, errors);\n validateOptionalString(link.rel, `${path}.rel`, errors);\n validateTarget(link.target, `${path}.target`, errors);\n}\n\nfunction validateAction(action: unknown, path: ValidationErrorPath, errors: string[]) {\n if (!isRecord(action)) {\n errors.push(`${path} must be an object.`);\n return;\n }\n\n validateRequiredString(action.label, `${path}.label`, errors);\n validateRequiredString(action.href, `${path}.href`, errors);\n validateSafeHref(action.href, `${path}.href`, errors);\n validateOptionalString(action.ariaLabel, `${path}.ariaLabel`, errors);\n validateOptionalString(action.rel, `${path}.rel`, errors);\n validateTarget(action.target, `${path}.target`, errors);\n\n if (action.variant != null) {\n if (typeof action.variant !== \"string\" || !CTA_VARIANTS.has(action.variant as NonNullable<BrandAction[\"variant\"]>)) {\n errors.push(`${path}.variant must be one of: primary, secondary, ghost.`);\n }\n }\n}\n\nfunction validateCustomSocialLink(link: unknown, path: ValidationErrorPath, errors: string[]) {\n if (!isRecord(link)) {\n errors.push(`${path} must be an object.`);\n return;\n }\n\n if (typeof link.platform !== \"string\" || link.platform.trim().length === 0) {\n errors.push(`${path}.platform must be a non-empty string.`);\n }\n validateRequiredString(link.label, `${path}.label`, errors);\n validateRequiredString(link.href, `${path}.href`, errors);\n validateSafeHref(link.href, `${path}.href`, errors);\n if (link.iconSvg != null) {\n validateOptionalString(link.iconSvg, `${path}.iconSvg`, errors);\n }\n}\n\nfunction validateTarget(target: unknown, path: ValidationErrorPath, errors: string[]) {\n if (target == null) return;\n if (typeof target !== \"string\" || !LINK_TARGETS.has(target as NonNullable<BrandNavLink[\"target\"]>)) {\n errors.push(`${path} must be one of: _blank, _self, _parent, _top.`);\n }\n}\n\nfunction validateCtaLayout(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || !CTA_LAYOUTS.has(value as NonNullable<BrandTheme[\"ctaLayout\"]>)) {\n errors.push(`${path} must be one of: inline, stacked.`);\n }\n}\n\nfunction validateRequiredString(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n errors.push(`${path} must be a non-empty string.`);\n }\n}\n\nfunction validateOptionalString(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || value.trim().length === 0) {\n errors.push(`${path} must be a non-empty string when provided.`);\n }\n}\n\nfunction validateSafeHref(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || value.trim().length === 0) return;\n if (!normalizeSafeHref(value)) {\n errors.push(`${path} must use a safe URL/path (http, https, mailto, tel, or relative path).`);\n }\n}\n\nfunction validateEmail(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || value.trim().length === 0) return;\n if (!normalizeEmailHref(value)) {\n errors.push(`${path} must be a valid email or mailto URL.`);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n"],"mappings":"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"}
package/dist/vue.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { l as shouldValidateInDev, n as assertValidBrandDetails, o as validateBrandDetails, r as assertValidBrandTheme, s as validateBrandTheme } from "./validation-D5bzM9TH.mjs";
1
+ import { l as shouldValidateInDev, n as assertValidBrandDetails, o as validateBrandDetails, r as assertValidBrandTheme, s as validateBrandTheme } from "./validation-BhhgC3n1.mjs";
2
2
  import { applyBrandShellProps, registerBrandShellElements } from "./web.mjs";
3
3
  import { defineComponent, h, onMounted, ref, watch } from "vue";
4
4
 
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.mts","names":[],"sources":["../src/web/index.ts"],"mappings":";;;cAyBM,eAAA,SAAwB,WAAA;AAAA,UAGb,iCAAA;EACf,aAAA;EACA,aAAA;AAAA;AAAA,UAGe,kBAAA;EACf,IAAA;EACA,SAAA;EACA,SAAA;EACA,MAAA;EACA,GAAA;AAAA;AAAA,UAGe,sBAAA;EACf,OAAA,EAAS,YAAA;EACT,KAAA,GAAQ,UAAA;EACR,UAAA;EACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA;AAAA;AAAA,KAGrC,qBAAA,GAAwB,WAAA;EAClC,OAAA,GAAU,YAAA;EACV,KAAA,GAAQ,UAAA;EACR,UAAA;EACA,WAAA,KAAgB,OAAA,EAAS,kBAAA,KAAuB,iBAAA;AAAA;AAAA,UAGjC,8BAAA;EACf,OAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,uBASa,qBAAA,SAA8B,eAAA;EAAA,WAChC,kBAAA,CAAA;EAAA,QAIH,QAAA;EAAA,QACA,MAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,IAEJ,OAAA,CAAA,GAAW,YAAA;EAAA,IAIX,OAAA,CAAQ,KAAA,EAAO,YAAA;EAAA,IAKf,KAAA,CAAA,GAAS,UAAA;EAAA,IAIT,KAAA,CAAM,KAAA,EAAO,UAAA;EAAA,IAKb,UAAA,CAAA;EAAA,IAIA,UAAA,CAAW,KAAA;EAAA,IAKX,WAAA,CAAA,KAAiB,OAAA,EAAS,kBAAA,KAAuB,iBAAA;EAAA,IAIjD,WAAA,CAAY,KAAA,IAAS,OAAA,EAAS,kBAAA,KAAuB,iBAAA;EAKzD,iBAAA,CAAA;EAeA,wBAAA,CAAyB,IAAA,UAAc,SAAA,iBAA0B,QAAA;EAAA,mBAW9C,KAAA,CACjB,OAAA,EAAS,YAAA,EACT,KAAA,EAAO,UAAA,SACP,UAAA,iBACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA,WAC9C,WAAA;EAAA,QAEK,MAAA;EAAA,QA2BA,eAAA;AAAA;AAAA,cASG,kBAAA,SAA2B,qBAAA;EAAA,UAC5B,KAAA,CACR,OAAA,EAAS,YAAA,EACT,KAAA,EAAO,UAAA,SACP,UAAA,iBACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA,WAC9C,WAAA;AAAA;AAAA,cAKQ,kBAAA,SAA2B,qBAAA;EAAA,UAC5B,KAAA,CACR,OAAA,EAAS,YAAA,EACT,KAAA,EAAO,UAAA,SACP,UAAA,iBACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA,WAC9C,WAAA;AAAA;AAAA,iBAKW,0BAAA,CAA2B,OAAA,GAAS,iCAAA;;;;iBAsBpC,oBAAA,CACd,OAAA,EAAS,qBAAA,qBACT,KAAA,EAAO,sBAAA;AAAA,iBAaO,6BAAA,CAA8B,KAAA,EAAO,sBAAA,GAAyB,8BAAA;AAAA,QAwYtE,MAAA;EAAA,UACI,qBAAA;IACR,cAAA,EAAgB,kBAAA;IAChB,cAAA,EAAgB,kBAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"web.d.mts","names":[],"sources":["../src/web/index.ts"],"mappings":";;;cAyBM,eAAA,SAAwB,WAAA;AAAA,UAGb,iCAAA;EACf,aAAA;EACA,aAAA;AAAA;AAAA,UAGe,kBAAA;EACf,IAAA;EACA,SAAA;EACA,SAAA;EACA,MAAA;EACA,GAAA;AAAA;AAAA,UAGe,sBAAA;EACf,OAAA,EAAS,YAAA;EACT,KAAA,GAAQ,UAAA;EACR,UAAA;EACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA;AAAA;AAAA,KAGrC,qBAAA,GAAwB,WAAA;EAClC,OAAA,GAAU,YAAA;EACV,KAAA,GAAQ,UAAA;EACR,UAAA;EACA,WAAA,KAAgB,OAAA,EAAS,kBAAA,KAAuB,iBAAA;AAAA;AAAA,UAGjC,8BAAA;EACf,OAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,uBASa,qBAAA,SAA8B,eAAA;EAAA,WAChC,kBAAA,CAAA;EAAA,QAIH,QAAA;EAAA,QACA,MAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,IAEJ,OAAA,CAAA,GAAW,YAAA;EAAA,IAIX,OAAA,CAAQ,KAAA,EAAO,YAAA;EAAA,IAKf,KAAA,CAAA,GAAS,UAAA;EAAA,IAIT,KAAA,CAAM,KAAA,EAAO,UAAA;EAAA,IAKb,UAAA,CAAA;EAAA,IAIA,UAAA,CAAW,KAAA;EAAA,IAKX,WAAA,CAAA,KAAiB,OAAA,EAAS,kBAAA,KAAuB,iBAAA;EAAA,IAIjD,WAAA,CAAY,KAAA,IAAS,OAAA,EAAS,kBAAA,KAAuB,iBAAA;EAKzD,iBAAA,CAAA;EAeA,wBAAA,CAAyB,IAAA,UAAc,SAAA,iBAA0B,QAAA;EAAA,mBAW9C,KAAA,CACjB,OAAA,EAAS,YAAA,EACT,KAAA,EAAO,UAAA,SACP,UAAA,iBACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA,WAC9C,WAAA;EAAA,QAEK,MAAA;EAAA,QA2BA,eAAA;AAAA;AAAA,cASG,kBAAA,SAA2B,qBAAA;EAAA,UAC5B,KAAA,CACR,OAAA,EAAS,YAAA,EACT,KAAA,EAAO,UAAA,SACP,UAAA,iBACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA,WAC9C,WAAA;AAAA;AAAA,cAKQ,kBAAA,SAA2B,qBAAA;EAAA,UAC5B,KAAA,CACR,OAAA,EAAS,YAAA,EACT,KAAA,EAAO,UAAA,SACP,UAAA,iBACA,WAAA,IAAe,OAAA,EAAS,kBAAA,KAAuB,iBAAA,WAC9C,WAAA;AAAA;AAAA,iBAKW,0BAAA,CAA2B,OAAA,GAAS,iCAAA;;;;iBAsBpC,oBAAA,CACd,OAAA,EAAS,qBAAA,qBACT,KAAA,EAAO,sBAAA;AAAA,iBAaO,6BAAA,CAA8B,KAAA,EAAO,sBAAA,GAAyB,8BAAA;AAAA,QAiZtE,MAAA;EAAA,UACI,qBAAA;IACR,cAAA,EAAgB,kBAAA;IAChB,cAAA,EAAgB,kBAAA;EAAA;AAAA"}
package/dist/web.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as normalizeBrandTheme, c as themeToCssVariables, l as shouldValidateInDev, n as assertValidBrandDetails, o as validateBrandDetails, r as assertValidBrandTheme, s as validateBrandTheme, t as BrandShellValidationError, u as buildShellViewModel } from "./validation-D5bzM9TH.mjs";
1
+ import { a as normalizeBrandTheme, c as themeToCssVariables, l as shouldValidateInDev, n as assertValidBrandDetails, o as validateBrandDetails, r as assertValidBrandTheme, s as validateBrandTheme, t as BrandShellValidationError, u as buildShellViewModel } from "./validation-BhhgC3n1.mjs";
2
2
 
3
3
  //#region src/web/index.ts
4
4
  const SVG_NS = "http://www.w3.org/2000/svg";
@@ -206,8 +206,14 @@ function createFooter(details, theme, shellClass, linkFactory) {
206
206
  img.src = details.logoSrc;
207
207
  img.alt = details.logoAlt ?? details.name;
208
208
  img.className = "brand-shell-footer__logo";
209
- brand.append(img);
210
- } else brand.append(createParagraph("brand-shell-footer__name", details.name));
209
+ if (details.homeHref) {
210
+ const identity = createAnchor(details.homeHref, "brand-shell-footer__name", details.name, `${details.name} home`, "_self", void 0, linkFactory);
211
+ identity.textContent = "";
212
+ identity.append(img);
213
+ brand.append(identity);
214
+ } else brand.append(img);
215
+ } else if (details.homeHref) brand.append(createAnchor(details.homeHref, "brand-shell-footer__name", details.name, `${details.name} home`, "_self", void 0, linkFactory));
216
+ else brand.append(createParagraph("brand-shell-footer__name", details.name));
211
217
  if (details.tagline) brand.append(createParagraph("brand-shell-footer__tagline", details.tagline));
212
218
  top.append(brand);
213
219
  const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(details);
package/dist/web.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.mjs","names":[],"sources":["../src/web/index.ts"],"sourcesContent":["import { buildShellViewModel, themeToCssVariables } from \"../core\";\nimport type {\n BrandDetails,\n BrandTheme,\n NormalizedBrandDetails,\n ShellActionLink,\n ShellNavLink,\n SocialLink,\n SocialPlatform,\n} from \"../core\";\nimport {\n BrandShellValidationError,\n assertValidBrandDetails,\n assertValidBrandTheme,\n normalizeBrandTheme,\n shouldValidateInDev,\n validateBrandDetails,\n validateBrandTheme,\n} from \"../core\";\n\nexport type { BrandAction, BrandDetails, BrandNavLink, BrandTheme } from \"../core\";\nexport { validateBrandDetails, validateBrandTheme } from \"../core\";\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\n\nconst HTMLElementBase: typeof HTMLElement =\n typeof HTMLElement === \"undefined\" ? (class {} as unknown as typeof HTMLElement) : HTMLElement;\n\nexport interface RegisterBrandShellElementsOptions {\n headerTagName?: string;\n footerTagName?: string;\n}\n\nexport interface LinkFactoryOptions {\n href: string;\n className: string;\n ariaLabel: string;\n target: string;\n rel?: string;\n}\n\nexport interface BrandShellElementProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n shellClass?: string | null;\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement;\n}\n\nexport type BrandShellElementLike = HTMLElement & {\n details?: BrandDetails | null;\n theme?: BrandTheme | null;\n shellClass?: string | null;\n linkFactory?: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null;\n};\n\nexport interface SerializedBrandShellAttributes {\n details: string;\n theme?: string;\n \"shell-class\"?: string;\n}\n\ninterface ParsedAttributes {\n details: BrandDetails | null;\n theme: BrandTheme | null;\n shellClass: string | null;\n}\n\nabstract class BaseBrandShellElement extends HTMLElementBase {\n static get observedAttributes() {\n return [\"details\", \"theme\", \"shell-class\"];\n }\n\n private _details: BrandDetails | null = null;\n private _theme: BrandTheme | null = null;\n private _shellClass: string | null = null;\n private _linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null = null;\n\n get details(): BrandDetails | null {\n return this._details;\n }\n\n set details(value: BrandDetails | null) {\n this._details = value;\n this.render();\n }\n\n get theme(): BrandTheme | null {\n return this._theme;\n }\n\n set theme(value: BrandTheme | null) {\n this._theme = value;\n this.render();\n }\n\n get shellClass(): string | null {\n return this._shellClass;\n }\n\n set shellClass(value: string | null) {\n this._shellClass = value;\n this.render();\n }\n\n get linkFactory(): ((options: LinkFactoryOptions) => HTMLAnchorElement) | null {\n return this._linkFactory;\n }\n\n set linkFactory(value: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null) {\n this._linkFactory = value;\n this.render();\n }\n\n connectedCallback() {\n this.upgradeProperty(\"details\");\n this.upgradeProperty(\"theme\");\n this.upgradeProperty(\"shellClass\");\n this.upgradeProperty(\"linkFactory\");\n\n const attrs = parseAttributes(this);\n if (this._details == null) this._details = attrs.details;\n if (this._theme == null) this._theme = attrs.theme;\n if (this._shellClass == null) this._shellClass = attrs.shellClass;\n\n if (this.style.display !== \"block\") this.style.display = \"block\";\n this.render();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {\n if (name === \"details\") {\n this._details = parseJsonAttribute<BrandDetails>(newValue);\n } else if (name === \"theme\") {\n this._theme = parseJsonAttribute<BrandTheme>(newValue);\n } else if (name === \"shell-class\") {\n this._shellClass = normalizeClassName(newValue);\n }\n this.render();\n }\n\n protected abstract build(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null,\n ): HTMLElement;\n\n private render() {\n if (this._details == null) {\n this.replaceChildren();\n return;\n }\n\n const detailsResult = validateBrandDetails(this._details);\n if (!detailsResult.valid) {\n if (shouldValidateInDev()) {\n throw new BrandShellValidationError(\"brand-shell/web details\", detailsResult.errors);\n }\n this.replaceChildren();\n return;\n }\n\n const themeResult = validateBrandTheme(this._theme);\n if (!themeResult.valid && shouldValidateInDev()) {\n throw new BrandShellValidationError(\"brand-shell/web theme\", themeResult.errors);\n }\n\n const normalizedDetails = detailsResult.normalized as NormalizedBrandDetails;\n const normalizedTheme = themeResult.normalized ?? null;\n\n const element = this.build(normalizedDetails, normalizedTheme, this._shellClass, this._linkFactory);\n this.replaceChildren(element);\n }\n\n private upgradeProperty(propertyName: \"details\" | \"theme\" | \"shellClass\" | \"linkFactory\") {\n if (Object.prototype.hasOwnProperty.call(this, propertyName)) {\n const value = (this as unknown as Record<string, unknown>)[propertyName];\n delete (this as unknown as Record<string, unknown>)[propertyName];\n (this as unknown as Record<string, unknown>)[propertyName] = value;\n }\n }\n}\n\nexport class BrandHeaderElement extends BaseBrandShellElement {\n protected build(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null,\n ): HTMLElement {\n return createHeader(details, theme, shellClass, linkFactory ?? undefined);\n }\n}\n\nexport class BrandFooterElement extends BaseBrandShellElement {\n protected build(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null,\n ): HTMLElement {\n return createFooter(details, theme, shellClass, linkFactory ?? undefined);\n }\n}\n\nexport function registerBrandShellElements(options: RegisterBrandShellElementsOptions = {}) {\n if (typeof customElements === \"undefined\") {\n throw new Error(\"Custom elements are not available in this environment.\");\n }\n\n const headerTagName = options.headerTagName ?? \"brand-header\";\n const footerTagName = options.footerTagName ?? \"brand-footer\";\n\n if (!customElements.get(headerTagName)) {\n const HeaderConstructor =\n headerTagName === \"brand-header\" ? BrandHeaderElement : class extends BrandHeaderElement {};\n customElements.define(headerTagName, HeaderConstructor);\n }\n if (!customElements.get(footerTagName)) {\n const FooterConstructor =\n footerTagName === \"brand-footer\" ? BrandFooterElement : class extends BrandFooterElement {};\n customElements.define(footerTagName, FooterConstructor);\n }\n\n return { headerTagName, footerTagName };\n}\n\nexport function applyBrandShellProps(\n element: BrandShellElementLike | null | undefined,\n props: BrandShellElementProps,\n) {\n if (!element) return;\n if (shouldValidateInDev()) {\n assertValidBrandDetails(props.details, \"brand-shell/web details\");\n assertValidBrandTheme(props.theme, \"brand-shell/web theme\");\n }\n element.details = validateBrandDetails(props.details).normalized ?? props.details;\n element.theme = normalizeBrandTheme(props.theme ?? null);\n element.shellClass = props.shellClass ?? null;\n element.linkFactory = props.linkFactory ?? null;\n}\n\nexport function serializeBrandShellAttributes(props: BrandShellElementProps): SerializedBrandShellAttributes {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(props.details, \"brand-shell/web serialize details\");\n assertValidBrandTheme(props.theme, \"brand-shell/web serialize theme\");\n }\n\n const normalizedDetails = validateBrandDetails(props.details).normalized ?? props.details;\n const normalizedTheme = normalizeBrandTheme(props.theme ?? null);\n\n const attributes: SerializedBrandShellAttributes = {\n details: JSON.stringify(normalizedDetails),\n };\n\n if (normalizedTheme) {\n attributes.theme = JSON.stringify(normalizedTheme);\n }\n\n const shellClass = normalizeClassName(props.shellClass ?? null);\n if (shellClass) {\n attributes[\"shell-class\"] = shellClass;\n }\n\n return attributes;\n}\n\nfunction parseAttributes(element: Element): ParsedAttributes {\n return {\n details: parseJsonAttribute<BrandDetails>(element.getAttribute(\"details\")),\n theme: parseJsonAttribute<BrandTheme>(element.getAttribute(\"theme\")),\n shellClass: normalizeClassName(element.getAttribute(\"shell-class\")),\n };\n}\n\nfunction parseJsonAttribute<T>(value: string | null): T | null {\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n}\n\nfunction normalizeClassName(value: string | null): string | null {\n if (!value) return null;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nfunction createHeader(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const header = document.createElement(\"header\");\n header.className = joinClassNames(\"brand-shell-header\", shellClass);\n header.setAttribute(\"role\", \"banner\");\n applyThemeVariables(header, theme);\n header.dataset.brandCtaLayout = resolveCtaLayout(theme);\n\n const inner = document.createElement(\"div\");\n inner.className = \"brand-shell-header__inner\";\n\n const identity = details.homeHref\n ? createAnchor(details.homeHref, \"brand-shell-header__name\", details.name, `${details.name} home`, \"_self\", undefined, linkFactory)\n : createSpan(\"brand-shell-header__name\", details.name);\n if (details.logoSrc) {\n const img = document.createElement(\"img\");\n img.src = details.logoSrc;\n img.alt = details.logoAlt ?? details.name;\n img.className = \"brand-shell-header__logo\";\n identity.textContent = \"\";\n identity.append(img);\n }\n inner.append(identity);\n\n const actions = document.createElement(\"div\");\n actions.className = \"brand-shell-header__actions\";\n\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(details);\n\n if (navLinks.length > 0) {\n actions.append(createNav(navLinks, \"brand-shell-header\", \"Primary\", linkFactory));\n }\n\n if (ctaLinks.length > 0) {\n actions.append(createCtas(ctaLinks, \"brand-shell-header__ctas\", linkFactory));\n }\n\n if (socialLinks.length > 0) {\n actions.append(createSocialLinks(socialLinks, \"brand-shell-header__social\", \"brand-shell-header__social-link\"));\n }\n\n inner.append(actions);\n header.append(inner);\n return header;\n}\n\nfunction createFooter(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const footer = document.createElement(\"footer\");\n footer.className = joinClassNames(\"brand-shell-footer\", shellClass);\n footer.setAttribute(\"role\", \"contentinfo\");\n applyThemeVariables(footer, theme);\n footer.dataset.brandCtaLayout = resolveCtaLayout(theme);\n\n const inner = document.createElement(\"div\");\n inner.className = \"brand-shell-footer__inner\";\n\n const top = document.createElement(\"div\");\n top.className = \"brand-shell-footer__top\";\n\n const brand = document.createElement(\"div\");\n brand.className = \"brand-shell-footer__brand\";\n if (details.logoSrc) {\n const img = document.createElement(\"img\");\n img.src = details.logoSrc;\n img.alt = details.logoAlt ?? details.name;\n img.className = \"brand-shell-footer__logo\";\n brand.append(img);\n } else {\n brand.append(createParagraph(\"brand-shell-footer__name\", details.name));\n }\n if (details.tagline) {\n brand.append(createParagraph(\"brand-shell-footer__tagline\", details.tagline));\n }\n top.append(brand);\n\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(details);\n\n if (navLinks.length > 0) {\n top.append(createNav(navLinks, \"brand-shell-footer\", \"Footer\", linkFactory));\n }\n\n if (ctaLinks.length > 0) {\n top.append(createCtas(ctaLinks, \"brand-shell-footer__ctas\", linkFactory));\n }\n\n if (socialLinks.length > 0) {\n top.append(createSocialLinks(socialLinks, \"brand-shell-footer__social\", \"brand-shell-footer__social-link\"));\n }\n\n const copy = createParagraph(\"brand-shell-footer__copy\", `© ${new Date().getFullYear()} ${details.name}`);\n\n inner.append(top, copy);\n footer.append(inner);\n return footer;\n}\n\nfunction createNav(\n links: ShellNavLink[],\n blockClass: \"brand-shell-header\" | \"brand-shell-footer\",\n ariaLabel: string,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const nav = document.createElement(\"nav\");\n nav.className = `${blockClass}__nav`;\n nav.setAttribute(\"aria-label\", ariaLabel);\n\n const list = document.createElement(\"ul\");\n list.className = `${blockClass}__list`;\n\n for (const link of links) {\n const item = document.createElement(\"li\");\n const anchor = createAnchor(link.href, `${blockClass}__link`, link.label, link.ariaLabel, link.target, link.rel, linkFactory);\n item.append(anchor);\n list.append(item);\n }\n\n nav.append(list);\n return nav;\n}\n\nfunction createCtas(\n actions: ShellActionLink[],\n containerClass: string,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const container = document.createElement(\"div\");\n container.className = containerClass;\n\n actions.forEach((action) => {\n const anchor = createAnchor(\n action.href,\n joinClassNames(\"brand-shell-button\", `brand-shell-button--${action.variant}`),\n action.label,\n action.ariaLabel,\n action.target,\n action.rel,\n linkFactory,\n );\n container.append(anchor);\n });\n\n return container;\n}\n\nfunction createSocialLinks(\n links: SocialLink[],\n containerClass: string,\n linkClass: string,\n): HTMLElement {\n const container = document.createElement(\"div\");\n container.className = containerClass;\n container.setAttribute(\"aria-label\", \"Social links\");\n\n for (const link of links) {\n const anchor = createAnchor(link.href, linkClass, \"\");\n anchor.setAttribute(\"aria-label\", link.label);\n if (!link.href.startsWith(\"mailto:\")) {\n anchor.target = \"_blank\";\n anchor.rel = \"noopener noreferrer\";\n }\n\n const icon = createSocialIcon(link.platform, link.iconSvg);\n if (icon) {\n anchor.append(icon);\n } else {\n anchor.append(createSpan(\"\", link.label[0] ?? \"?\"));\n }\n\n container.append(anchor);\n }\n\n return container;\n}\n\nfunction createSocialIcon(platform: SocialPlatform | string, iconSvg?: string): Element | null {\n switch (platform) {\n case \"github\":\n return createFilledIcon(\n \"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\",\n );\n case \"twitter\":\n return createFilledIcon(\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\");\n case \"linkedin\":\n return createFilledIcon(\n \"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\",\n );\n case \"discord\":\n return createFilledIcon(\n \"M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z\",\n );\n case \"email\":\n return createStrokedIcon([\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"], { rx: \"2\" });\n case \"website\":\n return createGlobeIcon();\n default:\n if (iconSvg) {\n const span = document.createElement(\"span\");\n span.setAttribute(\"aria-hidden\", \"true\");\n span.innerHTML = iconSvg;\n return span;\n }\n return null;\n }\n}\n\nfunction createFilledIcon(pathData: string): SVGSVGElement {\n const svg = createBaseSvg();\n svg.setAttribute(\"fill\", \"currentColor\");\n const path = document.createElementNS(SVG_NS, \"path\");\n path.setAttribute(\"d\", pathData);\n svg.append(path);\n return svg;\n}\n\nfunction createStrokedIcon(pathData: string[], rectAttributes?: Record<string, string>): SVGSVGElement {\n const svg = createBaseSvg();\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"2\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n\n if (rectAttributes) {\n const rect = document.createElementNS(SVG_NS, \"rect\");\n rect.setAttribute(\"width\", \"20\");\n rect.setAttribute(\"height\", \"16\");\n rect.setAttribute(\"x\", \"2\");\n rect.setAttribute(\"y\", \"4\");\n for (const [attribute, value] of Object.entries(rectAttributes)) {\n rect.setAttribute(attribute, value);\n }\n svg.append(rect);\n }\n\n for (const d of pathData) {\n const path = document.createElementNS(SVG_NS, \"path\");\n path.setAttribute(\"d\", d);\n svg.append(path);\n }\n\n return svg;\n}\n\nfunction createGlobeIcon(): SVGSVGElement {\n const svg = createBaseSvg();\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"2\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n\n const circle = document.createElementNS(SVG_NS, \"circle\");\n circle.setAttribute(\"cx\", \"12\");\n circle.setAttribute(\"cy\", \"12\");\n circle.setAttribute(\"r\", \"10\");\n svg.append(circle);\n\n for (const d of [\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\", \"M2 12h20\"]) {\n const path = document.createElementNS(SVG_NS, \"path\");\n path.setAttribute(\"d\", d);\n svg.append(path);\n }\n\n return svg;\n}\n\nfunction createBaseSvg(): SVGSVGElement {\n const svg = document.createElementNS(SVG_NS, \"svg\");\n svg.setAttribute(\"viewBox\", \"0 0 24 24\");\n svg.setAttribute(\"width\", \"1em\");\n svg.setAttribute(\"height\", \"1em\");\n svg.setAttribute(\"aria-hidden\", \"true\");\n return svg;\n}\n\nfunction applyThemeVariables(element: HTMLElement, theme: BrandTheme | null) {\n const style = themeToCssVariables(theme);\n for (const [name, value] of Object.entries(style)) {\n element.style.setProperty(name, value);\n }\n}\n\nfunction resolveCtaLayout(theme: BrandTheme | null): \"inline\" | \"stacked\" {\n return theme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n}\n\nfunction joinClassNames(...classNames: Array<string | null | undefined>) {\n return classNames.filter(Boolean).join(\" \");\n}\n\nfunction createAnchor(\n href: string,\n className: string,\n text: string,\n ariaLabel?: string,\n target?: string,\n rel?: string,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLAnchorElement {\n if (linkFactory) {\n const anchor = linkFactory({\n href,\n className,\n ariaLabel: ariaLabel ?? text,\n target: target ?? \"_self\",\n rel,\n });\n anchor.textContent = text;\n return anchor;\n }\n\n const anchor = document.createElement(\"a\");\n anchor.href = href;\n anchor.className = className;\n anchor.textContent = text;\n if (ariaLabel) anchor.setAttribute(\"aria-label\", ariaLabel);\n if (target) anchor.target = target;\n if (rel) anchor.rel = rel;\n return anchor;\n}\n\nfunction createParagraph(className: string, text: string): HTMLParagraphElement {\n const paragraph = document.createElement(\"p\");\n paragraph.className = className;\n paragraph.textContent = text;\n return paragraph;\n}\n\nfunction createSpan(className: string, text: string): HTMLSpanElement {\n const span = document.createElement(\"span\");\n span.className = className;\n span.textContent = text;\n return span;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"brand-header\": BrandHeaderElement;\n \"brand-footer\": BrandFooterElement;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"web.mjs","names":[],"sources":["../src/web/index.ts"],"sourcesContent":["import { buildShellViewModel, themeToCssVariables } from \"../core\";\nimport type {\n BrandDetails,\n BrandTheme,\n NormalizedBrandDetails,\n ShellActionLink,\n ShellNavLink,\n SocialLink,\n SocialPlatform,\n} from \"../core\";\nimport {\n BrandShellValidationError,\n assertValidBrandDetails,\n assertValidBrandTheme,\n normalizeBrandTheme,\n shouldValidateInDev,\n validateBrandDetails,\n validateBrandTheme,\n} from \"../core\";\n\nexport type { BrandAction, BrandDetails, BrandNavLink, BrandTheme } from \"../core\";\nexport { validateBrandDetails, validateBrandTheme } from \"../core\";\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\n\nconst HTMLElementBase: typeof HTMLElement =\n typeof HTMLElement === \"undefined\" ? (class {} as unknown as typeof HTMLElement) : HTMLElement;\n\nexport interface RegisterBrandShellElementsOptions {\n headerTagName?: string;\n footerTagName?: string;\n}\n\nexport interface LinkFactoryOptions {\n href: string;\n className: string;\n ariaLabel: string;\n target: string;\n rel?: string;\n}\n\nexport interface BrandShellElementProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n shellClass?: string | null;\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement;\n}\n\nexport type BrandShellElementLike = HTMLElement & {\n details?: BrandDetails | null;\n theme?: BrandTheme | null;\n shellClass?: string | null;\n linkFactory?: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null;\n};\n\nexport interface SerializedBrandShellAttributes {\n details: string;\n theme?: string;\n \"shell-class\"?: string;\n}\n\ninterface ParsedAttributes {\n details: BrandDetails | null;\n theme: BrandTheme | null;\n shellClass: string | null;\n}\n\nabstract class BaseBrandShellElement extends HTMLElementBase {\n static get observedAttributes() {\n return [\"details\", \"theme\", \"shell-class\"];\n }\n\n private _details: BrandDetails | null = null;\n private _theme: BrandTheme | null = null;\n private _shellClass: string | null = null;\n private _linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null = null;\n\n get details(): BrandDetails | null {\n return this._details;\n }\n\n set details(value: BrandDetails | null) {\n this._details = value;\n this.render();\n }\n\n get theme(): BrandTheme | null {\n return this._theme;\n }\n\n set theme(value: BrandTheme | null) {\n this._theme = value;\n this.render();\n }\n\n get shellClass(): string | null {\n return this._shellClass;\n }\n\n set shellClass(value: string | null) {\n this._shellClass = value;\n this.render();\n }\n\n get linkFactory(): ((options: LinkFactoryOptions) => HTMLAnchorElement) | null {\n return this._linkFactory;\n }\n\n set linkFactory(value: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null) {\n this._linkFactory = value;\n this.render();\n }\n\n connectedCallback() {\n this.upgradeProperty(\"details\");\n this.upgradeProperty(\"theme\");\n this.upgradeProperty(\"shellClass\");\n this.upgradeProperty(\"linkFactory\");\n\n const attrs = parseAttributes(this);\n if (this._details == null) this._details = attrs.details;\n if (this._theme == null) this._theme = attrs.theme;\n if (this._shellClass == null) this._shellClass = attrs.shellClass;\n\n if (this.style.display !== \"block\") this.style.display = \"block\";\n this.render();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {\n if (name === \"details\") {\n this._details = parseJsonAttribute<BrandDetails>(newValue);\n } else if (name === \"theme\") {\n this._theme = parseJsonAttribute<BrandTheme>(newValue);\n } else if (name === \"shell-class\") {\n this._shellClass = normalizeClassName(newValue);\n }\n this.render();\n }\n\n protected abstract build(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null,\n ): HTMLElement;\n\n private render() {\n if (this._details == null) {\n this.replaceChildren();\n return;\n }\n\n const detailsResult = validateBrandDetails(this._details);\n if (!detailsResult.valid) {\n if (shouldValidateInDev()) {\n throw new BrandShellValidationError(\"brand-shell/web details\", detailsResult.errors);\n }\n this.replaceChildren();\n return;\n }\n\n const themeResult = validateBrandTheme(this._theme);\n if (!themeResult.valid && shouldValidateInDev()) {\n throw new BrandShellValidationError(\"brand-shell/web theme\", themeResult.errors);\n }\n\n const normalizedDetails = detailsResult.normalized as NormalizedBrandDetails;\n const normalizedTheme = themeResult.normalized ?? null;\n\n const element = this.build(normalizedDetails, normalizedTheme, this._shellClass, this._linkFactory);\n this.replaceChildren(element);\n }\n\n private upgradeProperty(propertyName: \"details\" | \"theme\" | \"shellClass\" | \"linkFactory\") {\n if (Object.prototype.hasOwnProperty.call(this, propertyName)) {\n const value = (this as unknown as Record<string, unknown>)[propertyName];\n delete (this as unknown as Record<string, unknown>)[propertyName];\n (this as unknown as Record<string, unknown>)[propertyName] = value;\n }\n }\n}\n\nexport class BrandHeaderElement extends BaseBrandShellElement {\n protected build(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null,\n ): HTMLElement {\n return createHeader(details, theme, shellClass, linkFactory ?? undefined);\n }\n}\n\nexport class BrandFooterElement extends BaseBrandShellElement {\n protected build(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory: ((options: LinkFactoryOptions) => HTMLAnchorElement) | null,\n ): HTMLElement {\n return createFooter(details, theme, shellClass, linkFactory ?? undefined);\n }\n}\n\nexport function registerBrandShellElements(options: RegisterBrandShellElementsOptions = {}) {\n if (typeof customElements === \"undefined\") {\n throw new Error(\"Custom elements are not available in this environment.\");\n }\n\n const headerTagName = options.headerTagName ?? \"brand-header\";\n const footerTagName = options.footerTagName ?? \"brand-footer\";\n\n if (!customElements.get(headerTagName)) {\n const HeaderConstructor =\n headerTagName === \"brand-header\" ? BrandHeaderElement : class extends BrandHeaderElement {};\n customElements.define(headerTagName, HeaderConstructor);\n }\n if (!customElements.get(footerTagName)) {\n const FooterConstructor =\n footerTagName === \"brand-footer\" ? BrandFooterElement : class extends BrandFooterElement {};\n customElements.define(footerTagName, FooterConstructor);\n }\n\n return { headerTagName, footerTagName };\n}\n\nexport function applyBrandShellProps(\n element: BrandShellElementLike | null | undefined,\n props: BrandShellElementProps,\n) {\n if (!element) return;\n if (shouldValidateInDev()) {\n assertValidBrandDetails(props.details, \"brand-shell/web details\");\n assertValidBrandTheme(props.theme, \"brand-shell/web theme\");\n }\n element.details = validateBrandDetails(props.details).normalized ?? props.details;\n element.theme = normalizeBrandTheme(props.theme ?? null);\n element.shellClass = props.shellClass ?? null;\n element.linkFactory = props.linkFactory ?? null;\n}\n\nexport function serializeBrandShellAttributes(props: BrandShellElementProps): SerializedBrandShellAttributes {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(props.details, \"brand-shell/web serialize details\");\n assertValidBrandTheme(props.theme, \"brand-shell/web serialize theme\");\n }\n\n const normalizedDetails = validateBrandDetails(props.details).normalized ?? props.details;\n const normalizedTheme = normalizeBrandTheme(props.theme ?? null);\n\n const attributes: SerializedBrandShellAttributes = {\n details: JSON.stringify(normalizedDetails),\n };\n\n if (normalizedTheme) {\n attributes.theme = JSON.stringify(normalizedTheme);\n }\n\n const shellClass = normalizeClassName(props.shellClass ?? null);\n if (shellClass) {\n attributes[\"shell-class\"] = shellClass;\n }\n\n return attributes;\n}\n\nfunction parseAttributes(element: Element): ParsedAttributes {\n return {\n details: parseJsonAttribute<BrandDetails>(element.getAttribute(\"details\")),\n theme: parseJsonAttribute<BrandTheme>(element.getAttribute(\"theme\")),\n shellClass: normalizeClassName(element.getAttribute(\"shell-class\")),\n };\n}\n\nfunction parseJsonAttribute<T>(value: string | null): T | null {\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n}\n\nfunction normalizeClassName(value: string | null): string | null {\n if (!value) return null;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nfunction createHeader(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const header = document.createElement(\"header\");\n header.className = joinClassNames(\"brand-shell-header\", shellClass);\n header.setAttribute(\"role\", \"banner\");\n applyThemeVariables(header, theme);\n header.dataset.brandCtaLayout = resolveCtaLayout(theme);\n\n const inner = document.createElement(\"div\");\n inner.className = \"brand-shell-header__inner\";\n\n const identity = details.homeHref\n ? createAnchor(details.homeHref, \"brand-shell-header__name\", details.name, `${details.name} home`, \"_self\", undefined, linkFactory)\n : createSpan(\"brand-shell-header__name\", details.name);\n if (details.logoSrc) {\n const img = document.createElement(\"img\");\n img.src = details.logoSrc;\n img.alt = details.logoAlt ?? details.name;\n img.className = \"brand-shell-header__logo\";\n identity.textContent = \"\";\n identity.append(img);\n }\n inner.append(identity);\n\n const actions = document.createElement(\"div\");\n actions.className = \"brand-shell-header__actions\";\n\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(details);\n\n if (navLinks.length > 0) {\n actions.append(createNav(navLinks, \"brand-shell-header\", \"Primary\", linkFactory));\n }\n\n if (ctaLinks.length > 0) {\n actions.append(createCtas(ctaLinks, \"brand-shell-header__ctas\", linkFactory));\n }\n\n if (socialLinks.length > 0) {\n actions.append(createSocialLinks(socialLinks, \"brand-shell-header__social\", \"brand-shell-header__social-link\"));\n }\n\n inner.append(actions);\n header.append(inner);\n return header;\n}\n\nfunction createFooter(\n details: BrandDetails,\n theme: BrandTheme | null,\n shellClass: string | null,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const footer = document.createElement(\"footer\");\n footer.className = joinClassNames(\"brand-shell-footer\", shellClass);\n footer.setAttribute(\"role\", \"contentinfo\");\n applyThemeVariables(footer, theme);\n footer.dataset.brandCtaLayout = resolveCtaLayout(theme);\n\n const inner = document.createElement(\"div\");\n inner.className = \"brand-shell-footer__inner\";\n\n const top = document.createElement(\"div\");\n top.className = \"brand-shell-footer__top\";\n\n const brand = document.createElement(\"div\");\n brand.className = \"brand-shell-footer__brand\";\n if (details.logoSrc) {\n const img = document.createElement(\"img\");\n img.src = details.logoSrc;\n img.alt = details.logoAlt ?? details.name;\n img.className = \"brand-shell-footer__logo\";\n if (details.homeHref) {\n const identity = createAnchor(details.homeHref, \"brand-shell-footer__name\", details.name, `${details.name} home`, \"_self\", undefined, linkFactory);\n identity.textContent = \"\";\n identity.append(img);\n brand.append(identity);\n } else {\n brand.append(img);\n }\n } else if (details.homeHref) {\n brand.append(createAnchor(details.homeHref, \"brand-shell-footer__name\", details.name, `${details.name} home`, \"_self\", undefined, linkFactory));\n } else {\n brand.append(createParagraph(\"brand-shell-footer__name\", details.name));\n }\n if (details.tagline) {\n brand.append(createParagraph(\"brand-shell-footer__tagline\", details.tagline));\n }\n top.append(brand);\n\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(details);\n\n if (navLinks.length > 0) {\n top.append(createNav(navLinks, \"brand-shell-footer\", \"Footer\", linkFactory));\n }\n\n if (ctaLinks.length > 0) {\n top.append(createCtas(ctaLinks, \"brand-shell-footer__ctas\", linkFactory));\n }\n\n if (socialLinks.length > 0) {\n top.append(createSocialLinks(socialLinks, \"brand-shell-footer__social\", \"brand-shell-footer__social-link\"));\n }\n\n const copy = createParagraph(\"brand-shell-footer__copy\", `© ${new Date().getFullYear()} ${details.name}`);\n\n inner.append(top, copy);\n footer.append(inner);\n return footer;\n}\n\nfunction createNav(\n links: ShellNavLink[],\n blockClass: \"brand-shell-header\" | \"brand-shell-footer\",\n ariaLabel: string,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const nav = document.createElement(\"nav\");\n nav.className = `${blockClass}__nav`;\n nav.setAttribute(\"aria-label\", ariaLabel);\n\n const list = document.createElement(\"ul\");\n list.className = `${blockClass}__list`;\n\n for (const link of links) {\n const item = document.createElement(\"li\");\n const anchor = createAnchor(link.href, `${blockClass}__link`, link.label, link.ariaLabel, link.target, link.rel, linkFactory);\n item.append(anchor);\n list.append(item);\n }\n\n nav.append(list);\n return nav;\n}\n\nfunction createCtas(\n actions: ShellActionLink[],\n containerClass: string,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLElement {\n const container = document.createElement(\"div\");\n container.className = containerClass;\n\n actions.forEach((action) => {\n const anchor = createAnchor(\n action.href,\n joinClassNames(\"brand-shell-button\", `brand-shell-button--${action.variant}`),\n action.label,\n action.ariaLabel,\n action.target,\n action.rel,\n linkFactory,\n );\n container.append(anchor);\n });\n\n return container;\n}\n\nfunction createSocialLinks(\n links: SocialLink[],\n containerClass: string,\n linkClass: string,\n): HTMLElement {\n const container = document.createElement(\"div\");\n container.className = containerClass;\n container.setAttribute(\"aria-label\", \"Social links\");\n\n for (const link of links) {\n const anchor = createAnchor(link.href, linkClass, \"\");\n anchor.setAttribute(\"aria-label\", link.label);\n if (!link.href.startsWith(\"mailto:\")) {\n anchor.target = \"_blank\";\n anchor.rel = \"noopener noreferrer\";\n }\n\n const icon = createSocialIcon(link.platform, link.iconSvg);\n if (icon) {\n anchor.append(icon);\n } else {\n anchor.append(createSpan(\"\", link.label[0] ?? \"?\"));\n }\n\n container.append(anchor);\n }\n\n return container;\n}\n\nfunction createSocialIcon(platform: SocialPlatform | string, iconSvg?: string): Element | null {\n switch (platform) {\n case \"github\":\n return createFilledIcon(\n \"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\",\n );\n case \"twitter\":\n return createFilledIcon(\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\");\n case \"linkedin\":\n return createFilledIcon(\n \"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\",\n );\n case \"discord\":\n return createFilledIcon(\n \"M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z\",\n );\n case \"email\":\n return createStrokedIcon([\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"], { rx: \"2\" });\n case \"website\":\n return createGlobeIcon();\n default:\n if (iconSvg) {\n const span = document.createElement(\"span\");\n span.setAttribute(\"aria-hidden\", \"true\");\n span.innerHTML = iconSvg;\n return span;\n }\n return null;\n }\n}\n\nfunction createFilledIcon(pathData: string): SVGSVGElement {\n const svg = createBaseSvg();\n svg.setAttribute(\"fill\", \"currentColor\");\n const path = document.createElementNS(SVG_NS, \"path\");\n path.setAttribute(\"d\", pathData);\n svg.append(path);\n return svg;\n}\n\nfunction createStrokedIcon(pathData: string[], rectAttributes?: Record<string, string>): SVGSVGElement {\n const svg = createBaseSvg();\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"2\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n\n if (rectAttributes) {\n const rect = document.createElementNS(SVG_NS, \"rect\");\n rect.setAttribute(\"width\", \"20\");\n rect.setAttribute(\"height\", \"16\");\n rect.setAttribute(\"x\", \"2\");\n rect.setAttribute(\"y\", \"4\");\n for (const [attribute, value] of Object.entries(rectAttributes)) {\n rect.setAttribute(attribute, value);\n }\n svg.append(rect);\n }\n\n for (const d of pathData) {\n const path = document.createElementNS(SVG_NS, \"path\");\n path.setAttribute(\"d\", d);\n svg.append(path);\n }\n\n return svg;\n}\n\nfunction createGlobeIcon(): SVGSVGElement {\n const svg = createBaseSvg();\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"2\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n\n const circle = document.createElementNS(SVG_NS, \"circle\");\n circle.setAttribute(\"cx\", \"12\");\n circle.setAttribute(\"cy\", \"12\");\n circle.setAttribute(\"r\", \"10\");\n svg.append(circle);\n\n for (const d of [\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\", \"M2 12h20\"]) {\n const path = document.createElementNS(SVG_NS, \"path\");\n path.setAttribute(\"d\", d);\n svg.append(path);\n }\n\n return svg;\n}\n\nfunction createBaseSvg(): SVGSVGElement {\n const svg = document.createElementNS(SVG_NS, \"svg\");\n svg.setAttribute(\"viewBox\", \"0 0 24 24\");\n svg.setAttribute(\"width\", \"1em\");\n svg.setAttribute(\"height\", \"1em\");\n svg.setAttribute(\"aria-hidden\", \"true\");\n return svg;\n}\n\nfunction applyThemeVariables(element: HTMLElement, theme: BrandTheme | null) {\n const style = themeToCssVariables(theme);\n for (const [name, value] of Object.entries(style)) {\n element.style.setProperty(name, value);\n }\n}\n\nfunction resolveCtaLayout(theme: BrandTheme | null): \"inline\" | \"stacked\" {\n return theme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n}\n\nfunction joinClassNames(...classNames: Array<string | null | undefined>) {\n return classNames.filter(Boolean).join(\" \");\n}\n\nfunction createAnchor(\n href: string,\n className: string,\n text: string,\n ariaLabel?: string,\n target?: string,\n rel?: string,\n linkFactory?: (options: LinkFactoryOptions) => HTMLAnchorElement,\n): HTMLAnchorElement {\n if (linkFactory) {\n const anchor = linkFactory({\n href,\n className,\n ariaLabel: ariaLabel ?? text,\n target: target ?? \"_self\",\n rel,\n });\n anchor.textContent = text;\n return anchor;\n }\n\n const anchor = document.createElement(\"a\");\n anchor.href = href;\n anchor.className = className;\n anchor.textContent = text;\n if (ariaLabel) anchor.setAttribute(\"aria-label\", ariaLabel);\n if (target) anchor.target = target;\n if (rel) anchor.rel = rel;\n return anchor;\n}\n\nfunction createParagraph(className: string, text: string): HTMLParagraphElement {\n const paragraph = document.createElement(\"p\");\n paragraph.className = className;\n paragraph.textContent = text;\n return paragraph;\n}\n\nfunction createSpan(className: string, text: string): HTMLSpanElement {\n const span = document.createElement(\"span\");\n span.className = className;\n span.textContent = text;\n return span;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"brand-header\": BrandHeaderElement;\n \"brand-footer\": BrandFooterElement;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brand-shell",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Reusable Header and Footer components with typed details and theme. Premium default UX, works in React, Vite, Next.js.",
5
5
  "homepage": "https://github.com/venwork-dev/brand-shell#readme",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation-D5bzM9TH.mjs","names":[],"sources":["../src/core/social.ts","../src/core/links.ts","../src/core/shell.ts","../src/core/dev.ts","../src/core/theme.ts","../src/core/validation.ts"],"sourcesContent":["import type { BrandDetails } from \"./types\";\n\nexport type SocialPlatform = \"website\" | \"linkedin\" | \"email\" | \"github\" | \"twitter\" | \"discord\";\n\nexport interface SocialLink {\n platform: SocialPlatform | string;\n href: string;\n label: string;\n iconSvg?: string;\n}\n\nexport function detailsToSocialLinks(details: BrandDetails): SocialLink[] {\n const links: SocialLink[] = [];\n if (details.website) links.push({ platform: \"website\", href: details.website, label: \"Website\" });\n if (details.linkedin) links.push({ platform: \"linkedin\", href: details.linkedin, label: \"LinkedIn\" });\n if (details.email) links.push({ platform: \"email\", href: details.email, label: \"Email\" });\n if (details.github) links.push({ platform: \"github\", href: details.github, label: \"GitHub\" });\n if (details.twitter) links.push({ platform: \"twitter\", href: details.twitter, label: \"Twitter\" });\n if (details.discord) links.push({ platform: \"discord\", href: details.discord, label: \"Discord\" });\n if (details.customSocialLinks) {\n for (const custom of details.customSocialLinks) {\n links.push({ platform: custom.platform, href: custom.href, label: custom.label, iconSvg: custom.iconSvg });\n }\n }\n return links;\n}\n","const ABSOLUTE_SCHEME_PATTERN = /^([a-zA-Z][a-zA-Z\\d+.-]*):/;\nconst UNSAFE_CHAR_PATTERN = /[\\u0000-\\u001f\\u007f]/;\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\"]);\nconst REQUIRED_BLANK_REL_TOKENS = [\"noopener\", \"noreferrer\"];\n\nexport function normalizeSafeHref(href: unknown): string | undefined {\n if (typeof href !== \"string\") return undefined;\n const trimmed = href.trim();\n if (trimmed.length === 0) return undefined;\n if (UNSAFE_CHAR_PATTERN.test(trimmed)) return undefined;\n if (trimmed.startsWith(\"//\")) return undefined;\n\n const schemeMatch = trimmed.match(ABSOLUTE_SCHEME_PATTERN);\n if (!schemeMatch) {\n return trimmed;\n }\n\n const protocol = `${schemeMatch[1]?.toLowerCase()}:`;\n if (!ALLOWED_PROTOCOLS.has(protocol)) {\n return undefined;\n }\n\n return trimmed;\n}\n\nexport function isSafeHref(href: unknown): boolean {\n return normalizeSafeHref(href) != null;\n}\n\nexport function normalizeRel(target: \"_blank\" | \"_self\" | \"_parent\" | \"_top\", rel?: string): string | undefined {\n const normalizedRel = typeof rel === \"string\" ? rel.trim() : \"\";\n if (target !== \"_blank\") {\n return normalizedRel.length > 0 ? normalizedRel : undefined;\n }\n\n const tokens = normalizedRel.length > 0 ? normalizedRel.split(/\\s+/).filter(Boolean) : [];\n const tokenSet = new Set(tokens.map((token) => token.toLowerCase()));\n\n for (const requiredToken of REQUIRED_BLANK_REL_TOKENS) {\n if (!tokenSet.has(requiredToken)) {\n tokens.push(requiredToken);\n }\n }\n\n return tokens.join(\" \");\n}\n","import { detailsToSocialLinks, type SocialLink } from \"./social\";\nimport type { BrandAction, BrandDetails, BrandNavLink, CustomSocialLink } from \"./types\";\nimport { normalizeRel, normalizeSafeHref } from \"./links\";\n\nexport type LinkTarget = NonNullable<BrandNavLink[\"target\"]>;\n\nexport interface ShellNavLink extends BrandNavLink {\n ariaLabel: string;\n rel?: string;\n target: LinkTarget;\n}\n\nexport interface ShellActionLink extends BrandAction {\n ariaLabel: string;\n rel?: string;\n target: LinkTarget;\n variant: NonNullable<BrandAction[\"variant\"]>;\n}\n\nexport interface ShellViewModel {\n navLinks: ShellNavLink[];\n ctaLinks: ShellActionLink[];\n socialLinks: SocialLink[];\n}\n\nexport type NormalizedActionLink = Omit<ShellActionLink, \"variant\"> & Pick<BrandAction, \"variant\">;\n\nexport interface NormalizedBrandDetails extends Omit<BrandDetails, \"navLinks\" | \"primaryAction\" | \"secondaryAction\"> {\n navLinks: ShellNavLink[];\n primaryAction?: NormalizedActionLink;\n secondaryAction?: NormalizedActionLink;\n}\n\nexport function normalizeNavLinks(navLinks: BrandNavLink[] = []): ShellNavLink[] {\n return navLinks.flatMap((link) => {\n const href = normalizeSafeHref(link.href);\n if (!href) return [];\n\n const { target, rel } = normalizeLinkTargetRel(link.target, link.rel);\n return {\n ...link,\n href,\n ariaLabel: link.ariaLabel ?? link.label,\n target,\n rel,\n };\n });\n}\n\nexport function normalizeBrandDetails(details: BrandDetails): NormalizedBrandDetails {\n const normalizedPrimaryAction = normalizeAction(details.primaryAction);\n const normalizedSecondaryAction = normalizeAction(details.secondaryAction);\n\n return {\n ...details,\n homeHref: normalizeSafeHref(details.homeHref),\n email: normalizeEmailHref(details.email),\n website: normalizeSafeHref(details.website),\n linkedin: normalizeSafeHref(details.linkedin),\n github: normalizeSafeHref(details.github),\n twitter: normalizeSafeHref(details.twitter),\n discord: normalizeSafeHref(details.discord),\n navLinks: normalizeNavLinks(details.navLinks),\n primaryAction: normalizedPrimaryAction,\n secondaryAction: normalizedSecondaryAction,\n customSocialLinks: normalizeCustomSocialLinks(details.customSocialLinks),\n logoSrc: normalizeSafeHref(details.logoSrc),\n logoAlt: details.logoAlt,\n };\n}\n\nexport function normalizeCtaLinks(\n primaryAction?: BrandAction,\n secondaryAction?: BrandAction,\n): ShellActionLink[] {\n const normalizedPrimaryAction = normalizeAction(primaryAction);\n const normalizedSecondaryAction = normalizeAction(secondaryAction);\n const actions = [normalizedSecondaryAction, normalizedPrimaryAction].filter(\n (action): action is NonNullable<typeof action> => Boolean(action),\n );\n\n return actions.map((action, index) => {\n const variant =\n action.variant ?? (action === normalizedPrimaryAction || index === actions.length - 1 ? \"primary\" : \"secondary\");\n\n return {\n ...action,\n variant,\n };\n });\n}\n\nexport function buildShellViewModelFromNormalized(normalized: NormalizedBrandDetails): ShellViewModel {\n return {\n navLinks: normalized.navLinks,\n ctaLinks: normalizeCtaLinks(normalized.primaryAction, normalized.secondaryAction),\n socialLinks: detailsToSocialLinks(normalized),\n };\n}\n\nexport function buildShellViewModel(details: BrandDetails): ShellViewModel {\n return buildShellViewModelFromNormalized(normalizeBrandDetails(details));\n}\n\nexport function normalizeEmailHref(email?: string): string | undefined {\n if (typeof email !== \"string\") return undefined;\n const trimmed = email.trim();\n if (trimmed.length === 0) return undefined;\n if (trimmed.toLowerCase().startsWith(\"mailto:\")) {\n const address = trimmed.slice(7).trim();\n if (address.length === 0) return undefined;\n return normalizeSafeHref(`mailto:${address}`);\n }\n return normalizeSafeHref(`mailto:${trimmed}`);\n}\n\nfunction normalizeCustomSocialLinks(links?: CustomSocialLink[]): CustomSocialLink[] | undefined {\n if (!links || links.length === 0) return undefined;\n const normalized: CustomSocialLink[] = [];\n for (const link of links) {\n const href = normalizeSafeHref(link.href);\n if (!href) continue;\n normalized.push({ ...link, href });\n }\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction normalizeAction(action?: BrandAction): NormalizedActionLink | undefined {\n if (!action) return undefined;\n\n const href = normalizeSafeHref(action.href);\n if (!href) return undefined;\n\n const { target, rel } = normalizeLinkTargetRel(action.target, action.rel);\n return {\n ...action,\n href,\n target,\n rel,\n ariaLabel: action.ariaLabel ?? action.label,\n };\n}\n\nexport function normalizeLinkTargetRel(target?: BrandNavLink[\"target\"], rel?: string) {\n const normalizedTarget: LinkTarget = target ?? \"_self\";\n const normalizedRel = normalizeRel(normalizedTarget, rel);\n return {\n target: normalizedTarget,\n rel: normalizedRel,\n };\n}\n","type ImportMetaEnv = {\n DEV?: boolean;\n MODE?: string;\n};\n\ntype ImportMetaLike = {\n env?: ImportMetaEnv;\n};\n\nexport function shouldValidateInDev(): boolean {\n const nodeEnv = typeof process !== \"undefined\" ? process.env?.NODE_ENV : undefined;\n if (typeof nodeEnv === \"string\") {\n return nodeEnv !== \"production\";\n }\n\n const { env } = import.meta as unknown as ImportMetaLike;\n if (typeof env?.DEV === \"boolean\") {\n return env.DEV;\n }\n\n return false;\n}\n","import type { BrandTheme } from \"./types\";\n\nconst THEME_VAR_PREFIX = \"brand\";\nconst DARK_TEXT = \"#0f172a\";\nconst LIGHT_TEXT = \"#f8fafc\";\n\nexport type ThemeVariables = Record<string, string>;\n\nexport function themeToCssVariables(theme?: BrandTheme | null): ThemeVariables {\n if (!theme) return {};\n const style: ThemeVariables = {};\n if (theme.primaryColor != null) style[`--${THEME_VAR_PREFIX}-primary`] = theme.primaryColor;\n if (theme.backgroundColor != null) style[`--${THEME_VAR_PREFIX}-bg`] = theme.backgroundColor;\n if (theme.textColor != null) style[`--${THEME_VAR_PREFIX}-text`] = theme.textColor;\n if (theme.fontFamily != null) style[`--${THEME_VAR_PREFIX}-font`] = theme.fontFamily;\n if (theme.linkColor != null) style[`--${THEME_VAR_PREFIX}-link`] = theme.linkColor;\n if (theme.socialIconSize != null) style[`--${THEME_VAR_PREFIX}-social-size`] = theme.socialIconSize;\n if (theme.buttonTextColor != null) {\n style[`--${THEME_VAR_PREFIX}-button-text`] = theme.buttonTextColor;\n } else if (theme.primaryColor != null) {\n const buttonTextColor = getAccessibleTextColor(theme.primaryColor);\n if (buttonTextColor) style[`--${THEME_VAR_PREFIX}-button-text`] = buttonTextColor;\n }\n if (theme.borderRadius != null) style[`--${THEME_VAR_PREFIX}-radius`] = theme.borderRadius;\n if (theme.headerHeight != null) style[`--${THEME_VAR_PREFIX}-header-height`] = theme.headerHeight;\n if (theme.footerPadding != null) style[`--${THEME_VAR_PREFIX}-footer-padding`] = theme.footerPadding;\n if (theme.secondaryButtonBg != null) style[`--${THEME_VAR_PREFIX}-button-secondary`] = theme.secondaryButtonBg;\n if (theme.logoHeight != null) style[`--${THEME_VAR_PREFIX}-logo-height`] = theme.logoHeight;\n return style;\n}\n\nfunction getAccessibleTextColor(backgroundColor: string): string | undefined {\n const rgb = parseColorToRgb(backgroundColor);\n if (!rgb) return undefined;\n\n const contrastWithDark = contrastRatio(rgb, { r: 15, g: 23, b: 42 });\n const contrastWithLight = contrastRatio(rgb, { r: 248, g: 250, b: 252 });\n\n return contrastWithDark > contrastWithLight ? DARK_TEXT : LIGHT_TEXT;\n}\n\n/**\n * Parses a hex (#rgb / #rrggbb) or rgb()/rgba() color string to RGB components.\n * hsl(), oklch(), and other formats are not supported and return undefined.\n */\nfunction parseColorToRgb(color: string): { r: number; g: number; b: number } | undefined {\n const trimmed = color.trim();\n\n const hexMatch = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(trimmed);\n if (hexMatch) {\n const value = hexMatch[1];\n if (value.length === 3) {\n return {\n r: Number.parseInt(value[0] + value[0], 16),\n g: Number.parseInt(value[1] + value[1], 16),\n b: Number.parseInt(value[2] + value[2], 16),\n };\n }\n return {\n r: Number.parseInt(value.slice(0, 2), 16),\n g: Number.parseInt(value.slice(2, 4), 16),\n b: Number.parseInt(value.slice(4, 6), 16),\n };\n }\n\n const rgbMatch = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/.exec(trimmed);\n if (rgbMatch) {\n return { r: +rgbMatch[1], g: +rgbMatch[2], b: +rgbMatch[3] };\n }\n\n return undefined;\n}\n\nfunction contrastRatio(\n first: { r: number; g: number; b: number },\n second: { r: number; g: number; b: number },\n): number {\n const firstLuminance = relativeLuminance(first);\n const secondLuminance = relativeLuminance(second);\n const lighter = Math.max(firstLuminance, secondLuminance);\n const darker = Math.min(firstLuminance, secondLuminance);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction relativeLuminance(color: { r: number; g: number; b: number }): number {\n const transform = (channel: number) => {\n const normalized = channel / 255;\n if (normalized <= 0.03928) return normalized / 12.92;\n return ((normalized + 0.055) / 1.055) ** 2.4;\n };\n\n const r = transform(color.r);\n const g = transform(color.g);\n const b = transform(color.b);\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n","import { normalizeBrandDetails, normalizeEmailHref, type NormalizedBrandDetails } from \"./shell\";\nimport { normalizeSafeHref } from \"./links\";\nimport type { BrandAction, BrandDetails, BrandNavLink, BrandTheme, CustomSocialLink } from \"./types\";\n\nconst LINK_TARGETS = new Set<NonNullable<BrandNavLink[\"target\"]>>([\"_blank\", \"_self\", \"_parent\", \"_top\"]);\nconst CTA_VARIANTS = new Set<NonNullable<BrandAction[\"variant\"]>>([\"primary\", \"secondary\", \"ghost\"]);\nconst CTA_LAYOUTS = new Set<NonNullable<BrandTheme[\"ctaLayout\"]>>([\"inline\", \"stacked\"]);\nconst THEME_KEYS = new Set<keyof BrandTheme>([\n \"primaryColor\",\n \"backgroundColor\",\n \"textColor\",\n \"fontFamily\",\n \"linkColor\",\n \"socialIconSize\",\n \"buttonTextColor\",\n \"ctaLayout\",\n \"borderRadius\",\n \"headerHeight\",\n \"footerPadding\",\n \"secondaryButtonBg\",\n \"logoHeight\",\n]);\n\ntype ValidationErrorPath = string;\n\nexport interface BrandValidationResult<T> {\n valid: boolean;\n errors: string[];\n normalized: T | null;\n}\n\nexport class BrandShellValidationError extends Error {\n readonly context: string;\n readonly errors: string[];\n\n constructor(context: string, errors: string[]) {\n super(formatValidationErrors(context, errors));\n this.name = \"BrandShellValidationError\";\n this.context = context;\n this.errors = errors;\n }\n}\n\nexport function validateBrandDetails(details: unknown): BrandValidationResult<NormalizedBrandDetails> {\n const errors: string[] = [];\n\n if (!isRecord(details)) {\n errors.push(\"details must be an object.\");\n return { valid: false, errors, normalized: null };\n }\n\n validateRequiredString(details.name, \"details.name\", errors);\n validateOptionalString(details.homeHref, \"details.homeHref\", errors);\n validateSafeHref(details.homeHref, \"details.homeHref\", errors);\n validateOptionalString(details.website, \"details.website\", errors);\n validateSafeHref(details.website, \"details.website\", errors);\n validateOptionalString(details.linkedin, \"details.linkedin\", errors);\n validateSafeHref(details.linkedin, \"details.linkedin\", errors);\n validateOptionalString(details.email, \"details.email\", errors);\n validateEmail(details.email, \"details.email\", errors);\n validateOptionalString(details.github, \"details.github\", errors);\n validateSafeHref(details.github, \"details.github\", errors);\n validateOptionalString(details.twitter, \"details.twitter\", errors);\n validateSafeHref(details.twitter, \"details.twitter\", errors);\n validateOptionalString(details.discord, \"details.discord\", errors);\n validateSafeHref(details.discord, \"details.discord\", errors);\n validateOptionalString(details.tagline, \"details.tagline\", errors);\n validateOptionalString(details.logoSrc, \"details.logoSrc\", errors);\n validateSafeHref(details.logoSrc, \"details.logoSrc\", errors);\n validateOptionalString(details.logoAlt, \"details.logoAlt\", errors);\n\n if (details.navLinks != null) {\n if (!Array.isArray(details.navLinks)) {\n errors.push(\"details.navLinks must be an array.\");\n } else {\n details.navLinks.forEach((link, index) => validateNavLink(link, `details.navLinks[${index}]`, errors));\n }\n }\n\n if (details.primaryAction != null) {\n validateAction(details.primaryAction, \"details.primaryAction\", errors);\n }\n if (details.secondaryAction != null) {\n validateAction(details.secondaryAction, \"details.secondaryAction\", errors);\n }\n\n if (details.customSocialLinks != null) {\n if (!Array.isArray(details.customSocialLinks)) {\n errors.push(\"details.customSocialLinks must be an array.\");\n } else {\n details.customSocialLinks.forEach((link, index) =>\n validateCustomSocialLink(link, `details.customSocialLinks[${index}]`, errors),\n );\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors, normalized: null };\n }\n\n return {\n valid: true,\n errors: [],\n normalized: normalizeBrandDetails(details as unknown as BrandDetails),\n };\n}\n\nexport function validateBrandTheme(theme: unknown): BrandValidationResult<BrandTheme | null> {\n if (theme == null) {\n return {\n valid: true,\n errors: [],\n normalized: null,\n };\n }\n\n const errors: string[] = [];\n\n if (!isRecord(theme)) {\n errors.push(\"theme must be an object when provided.\");\n return { valid: false, errors, normalized: null };\n }\n\n for (const key of Object.keys(theme)) {\n if (!THEME_KEYS.has(key as keyof BrandTheme)) {\n errors.push(`theme.${key} is not a supported theme key.`);\n continue;\n }\n if (key === \"ctaLayout\") {\n validateCtaLayout(theme[key], \"theme.ctaLayout\", errors);\n continue;\n }\n validateOptionalString(theme[key], `theme.${key}`, errors);\n }\n\n if (errors.length > 0) {\n return { valid: false, errors, normalized: null };\n }\n\n return {\n valid: true,\n errors: [],\n normalized: normalizeBrandTheme(theme as BrandTheme),\n };\n}\n\nexport function assertValidBrandDetails(details: unknown, context = \"BrandDetails\"): asserts details is BrandDetails {\n const result = validateBrandDetails(details);\n if (!result.valid) {\n throw new BrandShellValidationError(context, result.errors);\n }\n}\n\nexport function assertValidBrandTheme(theme: unknown, context = \"BrandTheme\"): asserts theme is BrandTheme | null | undefined {\n const result = validateBrandTheme(theme);\n if (!result.valid) {\n throw new BrandShellValidationError(context, result.errors);\n }\n}\n\nexport function normalizeBrandTheme(theme?: BrandTheme | null): BrandTheme | null {\n if (!theme) return null;\n\n const normalized: BrandTheme = {};\n for (const key of THEME_KEYS) {\n const value = theme[key];\n if (key === \"ctaLayout\") {\n if (typeof value === \"string\" && CTA_LAYOUTS.has(value as NonNullable<BrandTheme[\"ctaLayout\"]>)) {\n normalized[key] = value as BrandTheme[\"ctaLayout\"];\n }\n continue;\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length > 0) {\n normalized[key] = trimmed;\n }\n }\n }\n\n return Object.keys(normalized).length > 0 ? normalized : null;\n}\n\nexport function formatValidationErrors(context: string, errors: string[]): string {\n return `${context} validation failed:\\n${errors.map((error) => `- ${error}`).join(\"\\n\")}`;\n}\n\nfunction validateNavLink(link: unknown, path: ValidationErrorPath, errors: string[]) {\n if (!isRecord(link)) {\n errors.push(`${path} must be an object.`);\n return;\n }\n\n validateRequiredString(link.label, `${path}.label`, errors);\n validateRequiredString(link.href, `${path}.href`, errors);\n validateSafeHref(link.href, `${path}.href`, errors);\n validateOptionalString(link.ariaLabel, `${path}.ariaLabel`, errors);\n validateOptionalString(link.rel, `${path}.rel`, errors);\n validateTarget(link.target, `${path}.target`, errors);\n}\n\nfunction validateAction(action: unknown, path: ValidationErrorPath, errors: string[]) {\n if (!isRecord(action)) {\n errors.push(`${path} must be an object.`);\n return;\n }\n\n validateRequiredString(action.label, `${path}.label`, errors);\n validateRequiredString(action.href, `${path}.href`, errors);\n validateSafeHref(action.href, `${path}.href`, errors);\n validateOptionalString(action.ariaLabel, `${path}.ariaLabel`, errors);\n validateOptionalString(action.rel, `${path}.rel`, errors);\n validateTarget(action.target, `${path}.target`, errors);\n\n if (action.variant != null) {\n if (typeof action.variant !== \"string\" || !CTA_VARIANTS.has(action.variant as NonNullable<BrandAction[\"variant\"]>)) {\n errors.push(`${path}.variant must be one of: primary, secondary, ghost.`);\n }\n }\n}\n\nfunction validateCustomSocialLink(link: unknown, path: ValidationErrorPath, errors: string[]) {\n if (!isRecord(link)) {\n errors.push(`${path} must be an object.`);\n return;\n }\n\n if (typeof link.platform !== \"string\" || link.platform.trim().length === 0) {\n errors.push(`${path}.platform must be a non-empty string.`);\n }\n validateRequiredString(link.label, `${path}.label`, errors);\n validateRequiredString(link.href, `${path}.href`, errors);\n validateSafeHref(link.href, `${path}.href`, errors);\n if (link.iconSvg != null) {\n validateOptionalString(link.iconSvg, `${path}.iconSvg`, errors);\n }\n}\n\nfunction validateTarget(target: unknown, path: ValidationErrorPath, errors: string[]) {\n if (target == null) return;\n if (typeof target !== \"string\" || !LINK_TARGETS.has(target as NonNullable<BrandNavLink[\"target\"]>)) {\n errors.push(`${path} must be one of: _blank, _self, _parent, _top.`);\n }\n}\n\nfunction validateCtaLayout(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || !CTA_LAYOUTS.has(value as NonNullable<BrandTheme[\"ctaLayout\"]>)) {\n errors.push(`${path} must be one of: inline, stacked.`);\n }\n}\n\nfunction validateRequiredString(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n errors.push(`${path} must be a non-empty string.`);\n }\n}\n\nfunction validateOptionalString(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || value.trim().length === 0) {\n errors.push(`${path} must be a non-empty string when provided.`);\n }\n}\n\nfunction validateSafeHref(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || value.trim().length === 0) return;\n if (!normalizeSafeHref(value)) {\n errors.push(`${path} must use a safe URL/path (http, https, mailto, tel, or relative path).`);\n }\n}\n\nfunction validateEmail(value: unknown, path: ValidationErrorPath, errors: string[]) {\n if (value == null) return;\n if (typeof value !== \"string\" || value.trim().length === 0) return;\n if (!normalizeEmailHref(value)) {\n errors.push(`${path} must be a valid email or mailto URL.`);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n"],"mappings":"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"}