@power-seo/react
Advanced tools
+13
-1
@@ -196,3 +196,15 @@ 'use strict'; | ||
| { "aria-label": "Breadcrumb", className }, | ||
| react.createElement("ol", { style: { listStyle: "none", padding: 0, margin: 0, display: "flex", flexWrap: "wrap" } }, ...breadcrumbItems) | ||
| react.createElement( | ||
| "ol", | ||
| { | ||
| style: { | ||
| listStyle: "none", | ||
| padding: 0, | ||
| margin: 0, | ||
| display: "flex", | ||
| flexWrap: "wrap" | ||
| } | ||
| }, | ||
| ...breadcrumbItems | ||
| ) | ||
| ) | ||
@@ -199,0 +211,0 @@ ); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/context.ts","../src/head-tags.ts","../src/components/DefaultSEO.ts","../src/components/SEO.ts","../src/components/OpenGraph.ts","../src/components/TwitterCard.ts","../src/components/Canonical.ts","../src/components/Robots.ts","../src/components/Hreflang.ts","../src/components/Breadcrumb.ts"],"names":["createContext","useContext","createElement","Fragment","resolveTitle","buildMetaTags","buildLinkTags","buildOpenGraphTags","buildTwitterTags","resolveCanonical","buildRobotsContent"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// @power-seo/react — SEO Context for Default Configuration\n// ============================================================================\n\nimport { createContext, useContext } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\n\nexport const SEOContext = createContext<SEOConfig | null>(null);\n\n/**\n * Hook to access the default SEO configuration from the nearest DefaultSEO provider.\n */\nexport function useDefaultSEO(): SEOConfig | null {\n return useContext(SEOContext);\n}\n","// ============================================================================\n// @power-seo/react — Head Tag Rendering (React 19 native + fallback)\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { MetaTag, LinkTag } from '@power-seo/core';\n\n/**\n * Render meta tags as React elements.\n * In React 19, these automatically hoist to <head>.\n * In React 18, wrap with a Helmet provider or use a framework's Head component.\n */\nexport function renderMetaTags(tags: MetaTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string> = { content: tag.content };\n if (tag.name) props.name = tag.name;\n if (tag.property) props.property = tag.property;\n if (tag.httpEquiv) props.httpEquiv = tag.httpEquiv;\n props.key = `meta-${tag.name ?? tag.property ?? tag.httpEquiv ?? i}`;\n return createElement('meta', props);\n }),\n );\n}\n\n/**\n * Render link tags as React elements.\n */\nexport function renderLinkTags(tags: LinkTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string | undefined> = {\n rel: tag.rel,\n href: tag.href,\n key: `link-${tag.rel}-${tag.hreflang ?? i}`,\n };\n if (tag.hreflang) props.hrefLang = tag.hreflang;\n if (tag.type) props.type = tag.type;\n if (tag.sizes) props.sizes = tag.sizes;\n if (tag.media) props.media = tag.media;\n if (tag.as) props.as = tag.as;\n if (tag.crossOrigin) props.crossOrigin = tag.crossOrigin;\n return createElement('link', props);\n }),\n );\n}\n","// ============================================================================\n// @power-seo/react — <DefaultSEO> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { ReactNode } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { SEOContext } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport interface DefaultSEOProps extends SEOConfig {\n children?: ReactNode;\n}\n\n/**\n * Provide global default SEO configuration.\n * Renders default meta tags and wraps children with SEO context.\n *\n * @example\n * ```tsx\n * <DefaultSEO\n * titleTemplate=\"%s | My Site\"\n * defaultTitle=\"My Site\"\n * description=\"Default description\"\n * openGraph={{\n * type: 'website',\n * siteName: 'My Site',\n * }}\n * >\n * <App />\n * </DefaultSEO>\n * ```\n */\nexport function DefaultSEO({ children, ...config }: DefaultSEOProps) {\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n SEOContext.Provider,\n { value: config },\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n children,\n );\n}\n","// ============================================================================\n// @power-seo/react — <SEO> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { useDefaultSEO } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport type SEOProps = SEOConfig;\n\n/**\n * All-in-one SEO component for per-page meta tag management.\n * Merges with DefaultSEO context if available.\n *\n * In React 19, <title>, <meta>, and <link> tags automatically hoist to <head>.\n * In React 18, use with a Helmet provider or framework Head component.\n *\n * @example\n * ```tsx\n * <SEO\n * title=\"About Us\"\n * description=\"Learn about our company\"\n * canonical=\"https://example.com/about\"\n * openGraph={{\n * title: 'About Us',\n * description: 'Learn about our company',\n * images: [{ url: 'https://example.com/about-og.jpg', width: 1200, height: 630 }],\n * }}\n * twitter={{\n * cardType: 'summary_large_image',\n * }}\n * />\n * ```\n */\nexport function SEO(props: SEOProps) {\n const defaults = useDefaultSEO();\n\n // Merge page config with defaults\n const config: SEOConfig = {\n ...defaults,\n ...props,\n // Deep merge for nested objects\n openGraph: {\n ...defaults?.openGraph,\n ...props.openGraph,\n images: props.openGraph?.images ?? defaults?.openGraph?.images,\n videos: props.openGraph?.videos ?? defaults?.openGraph?.videos,\n },\n twitter: {\n ...defaults?.twitter,\n ...props.twitter,\n },\n additionalMetaTags: [\n ...(defaults?.additionalMetaTags ?? []),\n ...(props.additionalMetaTags ?? []),\n ],\n additionalLinkTags: [\n ...(defaults?.additionalLinkTags ?? []),\n ...(props.additionalLinkTags ?? []),\n ],\n languageAlternates: props.languageAlternates ?? defaults?.languageAlternates,\n // Use page-specific title template or default\n titleTemplate: props.titleTemplate ?? defaults?.titleTemplate,\n };\n\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n Fragment,\n null,\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n );\n}\n","// ============================================================================\n// @power-seo/react — <OpenGraph> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { OpenGraphConfig } from '@power-seo/core';\nimport { buildOpenGraphTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type OpenGraphProps = OpenGraphConfig;\n\n/**\n * Render Open Graph meta tags.\n *\n * @example\n * ```tsx\n * <OpenGraph\n * type=\"article\"\n * title=\"My Article\"\n * description=\"Article description\"\n * url=\"https://example.com/article\"\n * images={[{\n * url: 'https://example.com/og.jpg',\n * width: 1200,\n * height: 630,\n * alt: 'Article image',\n * }]}\n * article={{\n * publishedTime: '2025-01-01',\n * authors: ['https://example.com/author'],\n * tags: ['react', 'seo'],\n * }}\n * />\n * ```\n */\nexport function OpenGraph(props: OpenGraphProps) {\n const tags = buildOpenGraphTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <TwitterCard> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { TwitterCardConfig } from '@power-seo/core';\nimport { buildTwitterTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type TwitterCardProps = TwitterCardConfig;\n\n/**\n * Render Twitter Card meta tags.\n *\n * @example\n * ```tsx\n * <TwitterCard\n * cardType=\"summary_large_image\"\n * site=\"@mysite\"\n * creator=\"@author\"\n * title=\"My Article\"\n * description=\"Article description\"\n * image=\"https://example.com/twitter.jpg\"\n * imageAlt=\"Twitter card image\"\n * />\n * ```\n */\nexport function TwitterCard(props: TwitterCardProps) {\n const tags = buildTwitterTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <Canonical> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport { resolveCanonical } from '@power-seo/core';\n\nexport interface CanonicalProps {\n /** The canonical URL (absolute or relative to baseUrl) */\n url: string;\n /** Base URL for resolving relative paths */\n baseUrl?: string;\n /** Whether to add trailing slash (default: false) */\n trailingSlash?: boolean;\n}\n\n/**\n * Render a canonical link tag.\n *\n * @example\n * ```tsx\n * <Canonical url=\"https://example.com/blog/post\" />\n * // or with base URL:\n * <Canonical url=\"/blog/post\" baseUrl=\"https://example.com\" />\n * ```\n */\nexport function Canonical({ url, baseUrl, trailingSlash = false }: CanonicalProps) {\n let canonical = baseUrl ? resolveCanonical(baseUrl, url) : url;\n\n if (trailingSlash && !canonical.endsWith('/')) {\n canonical += '/';\n } else if (!trailingSlash && canonical.endsWith('/') && canonical !== url.replace(/\\/$/, '') + '/') {\n // Only strip trailing slash if it was explicitly added\n }\n\n return createElement('link', {\n rel: 'canonical',\n href: canonical,\n });\n}\n","// ============================================================================\n// @power-seo/react — <Robots> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { RobotsDirective } from '@power-seo/core';\nimport { buildRobotsContent } from '@power-seo/core';\n\nexport type RobotsProps = RobotsDirective;\n\n/**\n * Render a robots meta tag with per-page directives.\n *\n * @example\n * ```tsx\n * <Robots index={false} follow={true} maxSnippet={150} />\n * // Renders: <meta name=\"robots\" content=\"noindex, follow, max-snippet:150\" />\n * ```\n */\nexport function Robots(props: RobotsProps) {\n const content = buildRobotsContent(props);\n if (!content) return null;\n return createElement('meta', { name: 'robots', content });\n}\n","// ============================================================================\n// @power-seo/react — <Hreflang> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { HreflangConfig } from '@power-seo/core';\n\nexport interface HreflangProps {\n /** Language alternates */\n alternates: HreflangConfig[];\n /** Whether to include x-default (usually same as default language) */\n xDefault?: string;\n}\n\n/**\n * Render hreflang link tags for multi-language pages.\n *\n * @example\n * ```tsx\n * <Hreflang\n * alternates={[\n * { hrefLang: 'en', href: 'https://example.com/en/page' },\n * { hrefLang: 'fr', href: 'https://example.com/fr/page' },\n * { hrefLang: 'de', href: 'https://example.com/de/page' },\n * ]}\n * xDefault=\"https://example.com/en/page\"\n * />\n * ```\n */\nexport function Hreflang({ alternates, xDefault }: HreflangProps) {\n const links = alternates.map((alt) =>\n createElement('link', {\n key: `hreflang-${alt.hrefLang}`,\n rel: 'alternate',\n hrefLang: alt.hrefLang,\n href: alt.href,\n }),\n );\n\n if (xDefault) {\n links.push(\n createElement('link', {\n key: 'hreflang-x-default',\n rel: 'alternate',\n hrefLang: 'x-default',\n href: xDefault,\n }),\n );\n }\n\n return createElement(Fragment, null, ...links);\n}\n","// ============================================================================\n// @power-seo/react — <Breadcrumb> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\n\nexport interface BreadcrumbItem {\n name: string;\n url?: string;\n}\n\nexport interface BreadcrumbProps {\n /** Breadcrumb items from root to current page */\n items: BreadcrumbItem[];\n /** Separator between items (default: \" / \") */\n separator?: string;\n /** CSS class for the nav element */\n className?: string;\n /** CSS class for each link */\n linkClassName?: string;\n /** CSS class for the current (last) item */\n activeClassName?: string;\n /** Whether to render the JSON-LD alongside the visual breadcrumb (default: true) */\n includeJsonLd?: boolean;\n}\n\n/**\n * Visual breadcrumb navigation with optional BreadcrumbList JSON-LD.\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * items={[\n * { name: 'Home', url: '/' },\n * { name: 'Blog', url: '/blog' },\n * { name: 'Current Post' },\n * ]}\n * />\n * ```\n */\nexport function Breadcrumb({\n items,\n separator = ' / ',\n className,\n linkClassName,\n activeClassName,\n includeJsonLd = true,\n}: BreadcrumbProps) {\n // Build JSON-LD schema\n const jsonLdData = {\n '@context': 'https://schema.org' as const,\n '@type': 'BreadcrumbList' as const,\n itemListElement: items.map((item, index) => ({\n '@type': 'ListItem' as const,\n position: index + 1,\n name: item.name,\n ...(item.url ? { item: item.url } : {}),\n })),\n };\n\n const children: ReturnType<typeof createElement>[] = [];\n\n // Render visual breadcrumb\n const breadcrumbItems: ReturnType<typeof createElement>[] = [];\n items.forEach((item, index) => {\n if (index > 0) {\n breadcrumbItems.push(\n createElement('span', { key: `sep-${index}`, 'aria-hidden': 'true' }, separator),\n );\n }\n\n const isLast = index === items.length - 1;\n\n if (item.url && !isLast) {\n breadcrumbItems.push(\n createElement(\n 'a',\n { key: `item-${index}`, href: item.url, className: linkClassName },\n item.name,\n ),\n );\n } else {\n breadcrumbItems.push(\n createElement(\n 'span',\n {\n key: `item-${index}`,\n className: isLast ? activeClassName : undefined,\n 'aria-current': isLast ? 'page' : undefined,\n },\n item.name,\n ),\n );\n }\n });\n\n children.push(\n createElement(\n 'nav',\n { 'aria-label': 'Breadcrumb', className },\n createElement('ol', { style: { listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexWrap: 'wrap' as const } }, ...breadcrumbItems),\n ),\n );\n\n // Render JSON-LD\n if (includeJsonLd) {\n children.push(\n createElement('script', {\n key: 'breadcrumb-jsonld',\n type: 'application/ld+json',\n dangerouslySetInnerHTML: { __html: JSON.stringify(jsonLdData) },\n }),\n );\n }\n\n return createElement(Fragment, null, ...children);\n}\n"]} | ||
| {"version":3,"sources":["../src/context.ts","../src/head-tags.ts","../src/components/DefaultSEO.ts","../src/components/SEO.ts","../src/components/OpenGraph.ts","../src/components/TwitterCard.ts","../src/components/Canonical.ts","../src/components/Robots.ts","../src/components/Hreflang.ts","../src/components/Breadcrumb.ts"],"names":["createContext","useContext","createElement","Fragment","resolveTitle","buildMetaTags","buildLinkTags","buildOpenGraphTags","buildTwitterTags","resolveCanonical","buildRobotsContent"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// @power-seo/react — SEO Context for Default Configuration\n// ============================================================================\n\nimport { createContext, useContext } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\n\nexport const SEOContext = createContext<SEOConfig | null>(null);\n\n/**\n * Hook to access the default SEO configuration from the nearest DefaultSEO provider.\n */\nexport function useDefaultSEO(): SEOConfig | null {\n return useContext(SEOContext);\n}\n","// ============================================================================\n// @power-seo/react — Head Tag Rendering (React 19 native + fallback)\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { MetaTag, LinkTag } from '@power-seo/core';\n\n/**\n * Render meta tags as React elements.\n * In React 19, these automatically hoist to <head>.\n * In React 18, wrap with a Helmet provider or use a framework's Head component.\n */\nexport function renderMetaTags(tags: MetaTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string> = { content: tag.content };\n if (tag.name) props.name = tag.name;\n if (tag.property) props.property = tag.property;\n if (tag.httpEquiv) props.httpEquiv = tag.httpEquiv;\n props.key = `meta-${tag.name ?? tag.property ?? tag.httpEquiv ?? i}`;\n return createElement('meta', props);\n }),\n );\n}\n\n/**\n * Render link tags as React elements.\n */\nexport function renderLinkTags(tags: LinkTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string | undefined> = {\n rel: tag.rel,\n href: tag.href,\n key: `link-${tag.rel}-${tag.hreflang ?? i}`,\n };\n if (tag.hreflang) props.hrefLang = tag.hreflang;\n if (tag.type) props.type = tag.type;\n if (tag.sizes) props.sizes = tag.sizes;\n if (tag.media) props.media = tag.media;\n if (tag.as) props.as = tag.as;\n if (tag.crossOrigin) props.crossOrigin = tag.crossOrigin;\n return createElement('link', props);\n }),\n );\n}\n","// ============================================================================\n// @power-seo/react — <DefaultSEO> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { ReactNode } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { SEOContext } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport interface DefaultSEOProps extends SEOConfig {\n children?: ReactNode;\n}\n\n/**\n * Provide global default SEO configuration.\n * Renders default meta tags and wraps children with SEO context.\n *\n * @example\n * ```tsx\n * <DefaultSEO\n * titleTemplate=\"%s | My Site\"\n * defaultTitle=\"My Site\"\n * description=\"Default description\"\n * openGraph={{\n * type: 'website',\n * siteName: 'My Site',\n * }}\n * >\n * <App />\n * </DefaultSEO>\n * ```\n */\nexport function DefaultSEO({ children, ...config }: DefaultSEOProps) {\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n SEOContext.Provider,\n { value: config },\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n children,\n );\n}\n","// ============================================================================\n// @power-seo/react — <SEO> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { useDefaultSEO } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport type SEOProps = SEOConfig;\n\n/**\n * All-in-one SEO component for per-page meta tag management.\n * Merges with DefaultSEO context if available.\n *\n * In React 19, <title>, <meta>, and <link> tags automatically hoist to <head>.\n * In React 18, use with a Helmet provider or framework Head component.\n *\n * @example\n * ```tsx\n * <SEO\n * title=\"About Us\"\n * description=\"Learn about our company\"\n * canonical=\"https://example.com/about\"\n * openGraph={{\n * title: 'About Us',\n * description: 'Learn about our company',\n * images: [{ url: 'https://example.com/about-og.jpg', width: 1200, height: 630 }],\n * }}\n * twitter={{\n * cardType: 'summary_large_image',\n * }}\n * />\n * ```\n */\nexport function SEO(props: SEOProps) {\n const defaults = useDefaultSEO();\n\n // Merge page config with defaults\n const config: SEOConfig = {\n ...defaults,\n ...props,\n // Deep merge for nested objects\n openGraph: {\n ...defaults?.openGraph,\n ...props.openGraph,\n images: props.openGraph?.images ?? defaults?.openGraph?.images,\n videos: props.openGraph?.videos ?? defaults?.openGraph?.videos,\n },\n twitter: {\n ...defaults?.twitter,\n ...props.twitter,\n },\n additionalMetaTags: [\n ...(defaults?.additionalMetaTags ?? []),\n ...(props.additionalMetaTags ?? []),\n ],\n additionalLinkTags: [\n ...(defaults?.additionalLinkTags ?? []),\n ...(props.additionalLinkTags ?? []),\n ],\n languageAlternates: props.languageAlternates ?? defaults?.languageAlternates,\n // Use page-specific title template or default\n titleTemplate: props.titleTemplate ?? defaults?.titleTemplate,\n };\n\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n Fragment,\n null,\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n );\n}\n","// ============================================================================\n// @power-seo/react — <OpenGraph> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { OpenGraphConfig } from '@power-seo/core';\nimport { buildOpenGraphTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type OpenGraphProps = OpenGraphConfig;\n\n/**\n * Render Open Graph meta tags.\n *\n * @example\n * ```tsx\n * <OpenGraph\n * type=\"article\"\n * title=\"My Article\"\n * description=\"Article description\"\n * url=\"https://example.com/article\"\n * images={[{\n * url: 'https://example.com/og.jpg',\n * width: 1200,\n * height: 630,\n * alt: 'Article image',\n * }]}\n * article={{\n * publishedTime: '2025-01-01',\n * authors: ['https://example.com/author'],\n * tags: ['react', 'seo'],\n * }}\n * />\n * ```\n */\nexport function OpenGraph(props: OpenGraphProps) {\n const tags = buildOpenGraphTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <TwitterCard> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { TwitterCardConfig } from '@power-seo/core';\nimport { buildTwitterTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type TwitterCardProps = TwitterCardConfig;\n\n/**\n * Render Twitter Card meta tags.\n *\n * @example\n * ```tsx\n * <TwitterCard\n * cardType=\"summary_large_image\"\n * site=\"@mysite\"\n * creator=\"@author\"\n * title=\"My Article\"\n * description=\"Article description\"\n * image=\"https://example.com/twitter.jpg\"\n * imageAlt=\"Twitter card image\"\n * />\n * ```\n */\nexport function TwitterCard(props: TwitterCardProps) {\n const tags = buildTwitterTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <Canonical> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport { resolveCanonical } from '@power-seo/core';\n\nexport interface CanonicalProps {\n /** The canonical URL (absolute or relative to baseUrl) */\n url: string;\n /** Base URL for resolving relative paths */\n baseUrl?: string;\n /** Whether to add trailing slash (default: false) */\n trailingSlash?: boolean;\n}\n\n/**\n * Render a canonical link tag.\n *\n * @example\n * ```tsx\n * <Canonical url=\"https://example.com/blog/post\" />\n * // or with base URL:\n * <Canonical url=\"/blog/post\" baseUrl=\"https://example.com\" />\n * ```\n */\nexport function Canonical({ url, baseUrl, trailingSlash = false }: CanonicalProps) {\n let canonical = baseUrl ? resolveCanonical(baseUrl, url) : url;\n\n if (trailingSlash && !canonical.endsWith('/')) {\n canonical += '/';\n } else if (\n !trailingSlash &&\n canonical.endsWith('/') &&\n canonical !== url.replace(/\\/$/, '') + '/'\n ) {\n // Only strip trailing slash if it was explicitly added\n }\n\n return createElement('link', {\n rel: 'canonical',\n href: canonical,\n });\n}\n","// ============================================================================\n// @power-seo/react — <Robots> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { RobotsDirective } from '@power-seo/core';\nimport { buildRobotsContent } from '@power-seo/core';\n\nexport type RobotsProps = RobotsDirective;\n\n/**\n * Render a robots meta tag with per-page directives.\n *\n * @example\n * ```tsx\n * <Robots index={false} follow={true} maxSnippet={150} />\n * // Renders: <meta name=\"robots\" content=\"noindex, follow, max-snippet:150\" />\n * ```\n */\nexport function Robots(props: RobotsProps) {\n const content = buildRobotsContent(props);\n if (!content) return null;\n return createElement('meta', { name: 'robots', content });\n}\n","// ============================================================================\n// @power-seo/react — <Hreflang> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { HreflangConfig } from '@power-seo/core';\n\nexport interface HreflangProps {\n /** Language alternates */\n alternates: HreflangConfig[];\n /** Whether to include x-default (usually same as default language) */\n xDefault?: string;\n}\n\n/**\n * Render hreflang link tags for multi-language pages.\n *\n * @example\n * ```tsx\n * <Hreflang\n * alternates={[\n * { hrefLang: 'en', href: 'https://example.com/en/page' },\n * { hrefLang: 'fr', href: 'https://example.com/fr/page' },\n * { hrefLang: 'de', href: 'https://example.com/de/page' },\n * ]}\n * xDefault=\"https://example.com/en/page\"\n * />\n * ```\n */\nexport function Hreflang({ alternates, xDefault }: HreflangProps) {\n const links = alternates.map((alt) =>\n createElement('link', {\n key: `hreflang-${alt.hrefLang}`,\n rel: 'alternate',\n hrefLang: alt.hrefLang,\n href: alt.href,\n }),\n );\n\n if (xDefault) {\n links.push(\n createElement('link', {\n key: 'hreflang-x-default',\n rel: 'alternate',\n hrefLang: 'x-default',\n href: xDefault,\n }),\n );\n }\n\n return createElement(Fragment, null, ...links);\n}\n","// ============================================================================\n// @power-seo/react — <Breadcrumb> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\n\nexport interface BreadcrumbItem {\n name: string;\n url?: string;\n}\n\nexport interface BreadcrumbProps {\n /** Breadcrumb items from root to current page */\n items: BreadcrumbItem[];\n /** Separator between items (default: \" / \") */\n separator?: string;\n /** CSS class for the nav element */\n className?: string;\n /** CSS class for each link */\n linkClassName?: string;\n /** CSS class for the current (last) item */\n activeClassName?: string;\n /** Whether to render the JSON-LD alongside the visual breadcrumb (default: true) */\n includeJsonLd?: boolean;\n}\n\n/**\n * Visual breadcrumb navigation with optional BreadcrumbList JSON-LD.\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * items={[\n * { name: 'Home', url: '/' },\n * { name: 'Blog', url: '/blog' },\n * { name: 'Current Post' },\n * ]}\n * />\n * ```\n */\nexport function Breadcrumb({\n items,\n separator = ' / ',\n className,\n linkClassName,\n activeClassName,\n includeJsonLd = true,\n}: BreadcrumbProps) {\n // Build JSON-LD schema\n const jsonLdData = {\n '@context': 'https://schema.org' as const,\n '@type': 'BreadcrumbList' as const,\n itemListElement: items.map((item, index) => ({\n '@type': 'ListItem' as const,\n position: index + 1,\n name: item.name,\n ...(item.url ? { item: item.url } : {}),\n })),\n };\n\n const children: ReturnType<typeof createElement>[] = [];\n\n // Render visual breadcrumb\n const breadcrumbItems: ReturnType<typeof createElement>[] = [];\n items.forEach((item, index) => {\n if (index > 0) {\n breadcrumbItems.push(\n createElement('span', { key: `sep-${index}`, 'aria-hidden': 'true' }, separator),\n );\n }\n\n const isLast = index === items.length - 1;\n\n if (item.url && !isLast) {\n breadcrumbItems.push(\n createElement(\n 'a',\n { key: `item-${index}`, href: item.url, className: linkClassName },\n item.name,\n ),\n );\n } else {\n breadcrumbItems.push(\n createElement(\n 'span',\n {\n key: `item-${index}`,\n className: isLast ? activeClassName : undefined,\n 'aria-current': isLast ? 'page' : undefined,\n },\n item.name,\n ),\n );\n }\n });\n\n children.push(\n createElement(\n 'nav',\n { 'aria-label': 'Breadcrumb', className },\n createElement(\n 'ol',\n {\n style: {\n listStyle: 'none',\n padding: 0,\n margin: 0,\n display: 'flex',\n flexWrap: 'wrap' as const,\n },\n },\n ...breadcrumbItems,\n ),\n ),\n );\n\n // Render JSON-LD\n if (includeJsonLd) {\n children.push(\n createElement('script', {\n key: 'breadcrumb-jsonld',\n type: 'application/ld+json',\n dangerouslySetInnerHTML: { __html: JSON.stringify(jsonLdData) },\n }),\n );\n }\n\n return createElement(Fragment, null, ...children);\n}\n"]} |
+13
-1
@@ -194,3 +194,15 @@ import { createContext, useContext, createElement, Fragment } from 'react'; | ||
| { "aria-label": "Breadcrumb", className }, | ||
| createElement("ol", { style: { listStyle: "none", padding: 0, margin: 0, display: "flex", flexWrap: "wrap" } }, ...breadcrumbItems) | ||
| createElement( | ||
| "ol", | ||
| { | ||
| style: { | ||
| listStyle: "none", | ||
| padding: 0, | ||
| margin: 0, | ||
| display: "flex", | ||
| flexWrap: "wrap" | ||
| } | ||
| }, | ||
| ...breadcrumbItems | ||
| ) | ||
| ) | ||
@@ -197,0 +209,0 @@ ); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/context.ts","../src/head-tags.ts","../src/components/DefaultSEO.ts","../src/components/SEO.ts","../src/components/OpenGraph.ts","../src/components/TwitterCard.ts","../src/components/Canonical.ts","../src/components/Robots.ts","../src/components/Hreflang.ts","../src/components/Breadcrumb.ts"],"names":["createElement","resolveTitle","buildMetaTags","buildLinkTags","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["// ============================================================================\n// @power-seo/react — SEO Context for Default Configuration\n// ============================================================================\n\nimport { createContext, useContext } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\n\nexport const SEOContext = createContext<SEOConfig | null>(null);\n\n/**\n * Hook to access the default SEO configuration from the nearest DefaultSEO provider.\n */\nexport function useDefaultSEO(): SEOConfig | null {\n return useContext(SEOContext);\n}\n","// ============================================================================\n// @power-seo/react — Head Tag Rendering (React 19 native + fallback)\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { MetaTag, LinkTag } from '@power-seo/core';\n\n/**\n * Render meta tags as React elements.\n * In React 19, these automatically hoist to <head>.\n * In React 18, wrap with a Helmet provider or use a framework's Head component.\n */\nexport function renderMetaTags(tags: MetaTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string> = { content: tag.content };\n if (tag.name) props.name = tag.name;\n if (tag.property) props.property = tag.property;\n if (tag.httpEquiv) props.httpEquiv = tag.httpEquiv;\n props.key = `meta-${tag.name ?? tag.property ?? tag.httpEquiv ?? i}`;\n return createElement('meta', props);\n }),\n );\n}\n\n/**\n * Render link tags as React elements.\n */\nexport function renderLinkTags(tags: LinkTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string | undefined> = {\n rel: tag.rel,\n href: tag.href,\n key: `link-${tag.rel}-${tag.hreflang ?? i}`,\n };\n if (tag.hreflang) props.hrefLang = tag.hreflang;\n if (tag.type) props.type = tag.type;\n if (tag.sizes) props.sizes = tag.sizes;\n if (tag.media) props.media = tag.media;\n if (tag.as) props.as = tag.as;\n if (tag.crossOrigin) props.crossOrigin = tag.crossOrigin;\n return createElement('link', props);\n }),\n );\n}\n","// ============================================================================\n// @power-seo/react — <DefaultSEO> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { ReactNode } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { SEOContext } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport interface DefaultSEOProps extends SEOConfig {\n children?: ReactNode;\n}\n\n/**\n * Provide global default SEO configuration.\n * Renders default meta tags and wraps children with SEO context.\n *\n * @example\n * ```tsx\n * <DefaultSEO\n * titleTemplate=\"%s | My Site\"\n * defaultTitle=\"My Site\"\n * description=\"Default description\"\n * openGraph={{\n * type: 'website',\n * siteName: 'My Site',\n * }}\n * >\n * <App />\n * </DefaultSEO>\n * ```\n */\nexport function DefaultSEO({ children, ...config }: DefaultSEOProps) {\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n SEOContext.Provider,\n { value: config },\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n children,\n );\n}\n","// ============================================================================\n// @power-seo/react — <SEO> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { useDefaultSEO } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport type SEOProps = SEOConfig;\n\n/**\n * All-in-one SEO component for per-page meta tag management.\n * Merges with DefaultSEO context if available.\n *\n * In React 19, <title>, <meta>, and <link> tags automatically hoist to <head>.\n * In React 18, use with a Helmet provider or framework Head component.\n *\n * @example\n * ```tsx\n * <SEO\n * title=\"About Us\"\n * description=\"Learn about our company\"\n * canonical=\"https://example.com/about\"\n * openGraph={{\n * title: 'About Us',\n * description: 'Learn about our company',\n * images: [{ url: 'https://example.com/about-og.jpg', width: 1200, height: 630 }],\n * }}\n * twitter={{\n * cardType: 'summary_large_image',\n * }}\n * />\n * ```\n */\nexport function SEO(props: SEOProps) {\n const defaults = useDefaultSEO();\n\n // Merge page config with defaults\n const config: SEOConfig = {\n ...defaults,\n ...props,\n // Deep merge for nested objects\n openGraph: {\n ...defaults?.openGraph,\n ...props.openGraph,\n images: props.openGraph?.images ?? defaults?.openGraph?.images,\n videos: props.openGraph?.videos ?? defaults?.openGraph?.videos,\n },\n twitter: {\n ...defaults?.twitter,\n ...props.twitter,\n },\n additionalMetaTags: [\n ...(defaults?.additionalMetaTags ?? []),\n ...(props.additionalMetaTags ?? []),\n ],\n additionalLinkTags: [\n ...(defaults?.additionalLinkTags ?? []),\n ...(props.additionalLinkTags ?? []),\n ],\n languageAlternates: props.languageAlternates ?? defaults?.languageAlternates,\n // Use page-specific title template or default\n titleTemplate: props.titleTemplate ?? defaults?.titleTemplate,\n };\n\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n Fragment,\n null,\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n );\n}\n","// ============================================================================\n// @power-seo/react — <OpenGraph> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { OpenGraphConfig } from '@power-seo/core';\nimport { buildOpenGraphTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type OpenGraphProps = OpenGraphConfig;\n\n/**\n * Render Open Graph meta tags.\n *\n * @example\n * ```tsx\n * <OpenGraph\n * type=\"article\"\n * title=\"My Article\"\n * description=\"Article description\"\n * url=\"https://example.com/article\"\n * images={[{\n * url: 'https://example.com/og.jpg',\n * width: 1200,\n * height: 630,\n * alt: 'Article image',\n * }]}\n * article={{\n * publishedTime: '2025-01-01',\n * authors: ['https://example.com/author'],\n * tags: ['react', 'seo'],\n * }}\n * />\n * ```\n */\nexport function OpenGraph(props: OpenGraphProps) {\n const tags = buildOpenGraphTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <TwitterCard> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { TwitterCardConfig } from '@power-seo/core';\nimport { buildTwitterTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type TwitterCardProps = TwitterCardConfig;\n\n/**\n * Render Twitter Card meta tags.\n *\n * @example\n * ```tsx\n * <TwitterCard\n * cardType=\"summary_large_image\"\n * site=\"@mysite\"\n * creator=\"@author\"\n * title=\"My Article\"\n * description=\"Article description\"\n * image=\"https://example.com/twitter.jpg\"\n * imageAlt=\"Twitter card image\"\n * />\n * ```\n */\nexport function TwitterCard(props: TwitterCardProps) {\n const tags = buildTwitterTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <Canonical> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport { resolveCanonical } from '@power-seo/core';\n\nexport interface CanonicalProps {\n /** The canonical URL (absolute or relative to baseUrl) */\n url: string;\n /** Base URL for resolving relative paths */\n baseUrl?: string;\n /** Whether to add trailing slash (default: false) */\n trailingSlash?: boolean;\n}\n\n/**\n * Render a canonical link tag.\n *\n * @example\n * ```tsx\n * <Canonical url=\"https://example.com/blog/post\" />\n * // or with base URL:\n * <Canonical url=\"/blog/post\" baseUrl=\"https://example.com\" />\n * ```\n */\nexport function Canonical({ url, baseUrl, trailingSlash = false }: CanonicalProps) {\n let canonical = baseUrl ? resolveCanonical(baseUrl, url) : url;\n\n if (trailingSlash && !canonical.endsWith('/')) {\n canonical += '/';\n } else if (!trailingSlash && canonical.endsWith('/') && canonical !== url.replace(/\\/$/, '') + '/') {\n // Only strip trailing slash if it was explicitly added\n }\n\n return createElement('link', {\n rel: 'canonical',\n href: canonical,\n });\n}\n","// ============================================================================\n// @power-seo/react — <Robots> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { RobotsDirective } from '@power-seo/core';\nimport { buildRobotsContent } from '@power-seo/core';\n\nexport type RobotsProps = RobotsDirective;\n\n/**\n * Render a robots meta tag with per-page directives.\n *\n * @example\n * ```tsx\n * <Robots index={false} follow={true} maxSnippet={150} />\n * // Renders: <meta name=\"robots\" content=\"noindex, follow, max-snippet:150\" />\n * ```\n */\nexport function Robots(props: RobotsProps) {\n const content = buildRobotsContent(props);\n if (!content) return null;\n return createElement('meta', { name: 'robots', content });\n}\n","// ============================================================================\n// @power-seo/react — <Hreflang> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { HreflangConfig } from '@power-seo/core';\n\nexport interface HreflangProps {\n /** Language alternates */\n alternates: HreflangConfig[];\n /** Whether to include x-default (usually same as default language) */\n xDefault?: string;\n}\n\n/**\n * Render hreflang link tags for multi-language pages.\n *\n * @example\n * ```tsx\n * <Hreflang\n * alternates={[\n * { hrefLang: 'en', href: 'https://example.com/en/page' },\n * { hrefLang: 'fr', href: 'https://example.com/fr/page' },\n * { hrefLang: 'de', href: 'https://example.com/de/page' },\n * ]}\n * xDefault=\"https://example.com/en/page\"\n * />\n * ```\n */\nexport function Hreflang({ alternates, xDefault }: HreflangProps) {\n const links = alternates.map((alt) =>\n createElement('link', {\n key: `hreflang-${alt.hrefLang}`,\n rel: 'alternate',\n hrefLang: alt.hrefLang,\n href: alt.href,\n }),\n );\n\n if (xDefault) {\n links.push(\n createElement('link', {\n key: 'hreflang-x-default',\n rel: 'alternate',\n hrefLang: 'x-default',\n href: xDefault,\n }),\n );\n }\n\n return createElement(Fragment, null, ...links);\n}\n","// ============================================================================\n// @power-seo/react — <Breadcrumb> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\n\nexport interface BreadcrumbItem {\n name: string;\n url?: string;\n}\n\nexport interface BreadcrumbProps {\n /** Breadcrumb items from root to current page */\n items: BreadcrumbItem[];\n /** Separator between items (default: \" / \") */\n separator?: string;\n /** CSS class for the nav element */\n className?: string;\n /** CSS class for each link */\n linkClassName?: string;\n /** CSS class for the current (last) item */\n activeClassName?: string;\n /** Whether to render the JSON-LD alongside the visual breadcrumb (default: true) */\n includeJsonLd?: boolean;\n}\n\n/**\n * Visual breadcrumb navigation with optional BreadcrumbList JSON-LD.\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * items={[\n * { name: 'Home', url: '/' },\n * { name: 'Blog', url: '/blog' },\n * { name: 'Current Post' },\n * ]}\n * />\n * ```\n */\nexport function Breadcrumb({\n items,\n separator = ' / ',\n className,\n linkClassName,\n activeClassName,\n includeJsonLd = true,\n}: BreadcrumbProps) {\n // Build JSON-LD schema\n const jsonLdData = {\n '@context': 'https://schema.org' as const,\n '@type': 'BreadcrumbList' as const,\n itemListElement: items.map((item, index) => ({\n '@type': 'ListItem' as const,\n position: index + 1,\n name: item.name,\n ...(item.url ? { item: item.url } : {}),\n })),\n };\n\n const children: ReturnType<typeof createElement>[] = [];\n\n // Render visual breadcrumb\n const breadcrumbItems: ReturnType<typeof createElement>[] = [];\n items.forEach((item, index) => {\n if (index > 0) {\n breadcrumbItems.push(\n createElement('span', { key: `sep-${index}`, 'aria-hidden': 'true' }, separator),\n );\n }\n\n const isLast = index === items.length - 1;\n\n if (item.url && !isLast) {\n breadcrumbItems.push(\n createElement(\n 'a',\n { key: `item-${index}`, href: item.url, className: linkClassName },\n item.name,\n ),\n );\n } else {\n breadcrumbItems.push(\n createElement(\n 'span',\n {\n key: `item-${index}`,\n className: isLast ? activeClassName : undefined,\n 'aria-current': isLast ? 'page' : undefined,\n },\n item.name,\n ),\n );\n }\n });\n\n children.push(\n createElement(\n 'nav',\n { 'aria-label': 'Breadcrumb', className },\n createElement('ol', { style: { listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexWrap: 'wrap' as const } }, ...breadcrumbItems),\n ),\n );\n\n // Render JSON-LD\n if (includeJsonLd) {\n children.push(\n createElement('script', {\n key: 'breadcrumb-jsonld',\n type: 'application/ld+json',\n dangerouslySetInnerHTML: { __html: JSON.stringify(jsonLdData) },\n }),\n );\n }\n\n return createElement(Fragment, null, ...children);\n}\n"]} | ||
| {"version":3,"sources":["../src/context.ts","../src/head-tags.ts","../src/components/DefaultSEO.ts","../src/components/SEO.ts","../src/components/OpenGraph.ts","../src/components/TwitterCard.ts","../src/components/Canonical.ts","../src/components/Robots.ts","../src/components/Hreflang.ts","../src/components/Breadcrumb.ts"],"names":["createElement","resolveTitle","buildMetaTags","buildLinkTags","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["// ============================================================================\n// @power-seo/react — SEO Context for Default Configuration\n// ============================================================================\n\nimport { createContext, useContext } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\n\nexport const SEOContext = createContext<SEOConfig | null>(null);\n\n/**\n * Hook to access the default SEO configuration from the nearest DefaultSEO provider.\n */\nexport function useDefaultSEO(): SEOConfig | null {\n return useContext(SEOContext);\n}\n","// ============================================================================\n// @power-seo/react — Head Tag Rendering (React 19 native + fallback)\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { MetaTag, LinkTag } from '@power-seo/core';\n\n/**\n * Render meta tags as React elements.\n * In React 19, these automatically hoist to <head>.\n * In React 18, wrap with a Helmet provider or use a framework's Head component.\n */\nexport function renderMetaTags(tags: MetaTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string> = { content: tag.content };\n if (tag.name) props.name = tag.name;\n if (tag.property) props.property = tag.property;\n if (tag.httpEquiv) props.httpEquiv = tag.httpEquiv;\n props.key = `meta-${tag.name ?? tag.property ?? tag.httpEquiv ?? i}`;\n return createElement('meta', props);\n }),\n );\n}\n\n/**\n * Render link tags as React elements.\n */\nexport function renderLinkTags(tags: LinkTag[]) {\n return createElement(\n Fragment,\n null,\n ...tags.map((tag, i) => {\n const props: Record<string, string | undefined> = {\n rel: tag.rel,\n href: tag.href,\n key: `link-${tag.rel}-${tag.hreflang ?? i}`,\n };\n if (tag.hreflang) props.hrefLang = tag.hreflang;\n if (tag.type) props.type = tag.type;\n if (tag.sizes) props.sizes = tag.sizes;\n if (tag.media) props.media = tag.media;\n if (tag.as) props.as = tag.as;\n if (tag.crossOrigin) props.crossOrigin = tag.crossOrigin;\n return createElement('link', props);\n }),\n );\n}\n","// ============================================================================\n// @power-seo/react — <DefaultSEO> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { ReactNode } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { SEOContext } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport interface DefaultSEOProps extends SEOConfig {\n children?: ReactNode;\n}\n\n/**\n * Provide global default SEO configuration.\n * Renders default meta tags and wraps children with SEO context.\n *\n * @example\n * ```tsx\n * <DefaultSEO\n * titleTemplate=\"%s | My Site\"\n * defaultTitle=\"My Site\"\n * description=\"Default description\"\n * openGraph={{\n * type: 'website',\n * siteName: 'My Site',\n * }}\n * >\n * <App />\n * </DefaultSEO>\n * ```\n */\nexport function DefaultSEO({ children, ...config }: DefaultSEOProps) {\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n SEOContext.Provider,\n { value: config },\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n children,\n );\n}\n","// ============================================================================\n// @power-seo/react — <SEO> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { SEOConfig } from '@power-seo/core';\nimport { buildMetaTags, buildLinkTags, resolveTitle } from '@power-seo/core';\nimport { useDefaultSEO } from '../context.js';\nimport { renderMetaTags, renderLinkTags } from '../head-tags.js';\n\nexport type SEOProps = SEOConfig;\n\n/**\n * All-in-one SEO component for per-page meta tag management.\n * Merges with DefaultSEO context if available.\n *\n * In React 19, <title>, <meta>, and <link> tags automatically hoist to <head>.\n * In React 18, use with a Helmet provider or framework Head component.\n *\n * @example\n * ```tsx\n * <SEO\n * title=\"About Us\"\n * description=\"Learn about our company\"\n * canonical=\"https://example.com/about\"\n * openGraph={{\n * title: 'About Us',\n * description: 'Learn about our company',\n * images: [{ url: 'https://example.com/about-og.jpg', width: 1200, height: 630 }],\n * }}\n * twitter={{\n * cardType: 'summary_large_image',\n * }}\n * />\n * ```\n */\nexport function SEO(props: SEOProps) {\n const defaults = useDefaultSEO();\n\n // Merge page config with defaults\n const config: SEOConfig = {\n ...defaults,\n ...props,\n // Deep merge for nested objects\n openGraph: {\n ...defaults?.openGraph,\n ...props.openGraph,\n images: props.openGraph?.images ?? defaults?.openGraph?.images,\n videos: props.openGraph?.videos ?? defaults?.openGraph?.videos,\n },\n twitter: {\n ...defaults?.twitter,\n ...props.twitter,\n },\n additionalMetaTags: [\n ...(defaults?.additionalMetaTags ?? []),\n ...(props.additionalMetaTags ?? []),\n ],\n additionalLinkTags: [\n ...(defaults?.additionalLinkTags ?? []),\n ...(props.additionalLinkTags ?? []),\n ],\n languageAlternates: props.languageAlternates ?? defaults?.languageAlternates,\n // Use page-specific title template or default\n titleTemplate: props.titleTemplate ?? defaults?.titleTemplate,\n };\n\n const title = resolveTitle(config);\n const metaTags = buildMetaTags(config);\n const linkTags = buildLinkTags(config);\n\n return createElement(\n Fragment,\n null,\n title ? createElement('title', null, title) : null,\n renderMetaTags(metaTags),\n renderLinkTags(linkTags),\n );\n}\n","// ============================================================================\n// @power-seo/react — <OpenGraph> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { OpenGraphConfig } from '@power-seo/core';\nimport { buildOpenGraphTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type OpenGraphProps = OpenGraphConfig;\n\n/**\n * Render Open Graph meta tags.\n *\n * @example\n * ```tsx\n * <OpenGraph\n * type=\"article\"\n * title=\"My Article\"\n * description=\"Article description\"\n * url=\"https://example.com/article\"\n * images={[{\n * url: 'https://example.com/og.jpg',\n * width: 1200,\n * height: 630,\n * alt: 'Article image',\n * }]}\n * article={{\n * publishedTime: '2025-01-01',\n * authors: ['https://example.com/author'],\n * tags: ['react', 'seo'],\n * }}\n * />\n * ```\n */\nexport function OpenGraph(props: OpenGraphProps) {\n const tags = buildOpenGraphTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <TwitterCard> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { TwitterCardConfig } from '@power-seo/core';\nimport { buildTwitterTags } from '@power-seo/core';\nimport { renderMetaTags } from '../head-tags.js';\n\nexport type TwitterCardProps = TwitterCardConfig;\n\n/**\n * Render Twitter Card meta tags.\n *\n * @example\n * ```tsx\n * <TwitterCard\n * cardType=\"summary_large_image\"\n * site=\"@mysite\"\n * creator=\"@author\"\n * title=\"My Article\"\n * description=\"Article description\"\n * image=\"https://example.com/twitter.jpg\"\n * imageAlt=\"Twitter card image\"\n * />\n * ```\n */\nexport function TwitterCard(props: TwitterCardProps) {\n const tags = buildTwitterTags(props);\n return createElement(Fragment, null, renderMetaTags(tags));\n}\n","// ============================================================================\n// @power-seo/react — <Canonical> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport { resolveCanonical } from '@power-seo/core';\n\nexport interface CanonicalProps {\n /** The canonical URL (absolute or relative to baseUrl) */\n url: string;\n /** Base URL for resolving relative paths */\n baseUrl?: string;\n /** Whether to add trailing slash (default: false) */\n trailingSlash?: boolean;\n}\n\n/**\n * Render a canonical link tag.\n *\n * @example\n * ```tsx\n * <Canonical url=\"https://example.com/blog/post\" />\n * // or with base URL:\n * <Canonical url=\"/blog/post\" baseUrl=\"https://example.com\" />\n * ```\n */\nexport function Canonical({ url, baseUrl, trailingSlash = false }: CanonicalProps) {\n let canonical = baseUrl ? resolveCanonical(baseUrl, url) : url;\n\n if (trailingSlash && !canonical.endsWith('/')) {\n canonical += '/';\n } else if (\n !trailingSlash &&\n canonical.endsWith('/') &&\n canonical !== url.replace(/\\/$/, '') + '/'\n ) {\n // Only strip trailing slash if it was explicitly added\n }\n\n return createElement('link', {\n rel: 'canonical',\n href: canonical,\n });\n}\n","// ============================================================================\n// @power-seo/react — <Robots> Component\n// ============================================================================\n\nimport { createElement } from 'react';\nimport type { RobotsDirective } from '@power-seo/core';\nimport { buildRobotsContent } from '@power-seo/core';\n\nexport type RobotsProps = RobotsDirective;\n\n/**\n * Render a robots meta tag with per-page directives.\n *\n * @example\n * ```tsx\n * <Robots index={false} follow={true} maxSnippet={150} />\n * // Renders: <meta name=\"robots\" content=\"noindex, follow, max-snippet:150\" />\n * ```\n */\nexport function Robots(props: RobotsProps) {\n const content = buildRobotsContent(props);\n if (!content) return null;\n return createElement('meta', { name: 'robots', content });\n}\n","// ============================================================================\n// @power-seo/react — <Hreflang> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\nimport type { HreflangConfig } from '@power-seo/core';\n\nexport interface HreflangProps {\n /** Language alternates */\n alternates: HreflangConfig[];\n /** Whether to include x-default (usually same as default language) */\n xDefault?: string;\n}\n\n/**\n * Render hreflang link tags for multi-language pages.\n *\n * @example\n * ```tsx\n * <Hreflang\n * alternates={[\n * { hrefLang: 'en', href: 'https://example.com/en/page' },\n * { hrefLang: 'fr', href: 'https://example.com/fr/page' },\n * { hrefLang: 'de', href: 'https://example.com/de/page' },\n * ]}\n * xDefault=\"https://example.com/en/page\"\n * />\n * ```\n */\nexport function Hreflang({ alternates, xDefault }: HreflangProps) {\n const links = alternates.map((alt) =>\n createElement('link', {\n key: `hreflang-${alt.hrefLang}`,\n rel: 'alternate',\n hrefLang: alt.hrefLang,\n href: alt.href,\n }),\n );\n\n if (xDefault) {\n links.push(\n createElement('link', {\n key: 'hreflang-x-default',\n rel: 'alternate',\n hrefLang: 'x-default',\n href: xDefault,\n }),\n );\n }\n\n return createElement(Fragment, null, ...links);\n}\n","// ============================================================================\n// @power-seo/react — <Breadcrumb> Component\n// ============================================================================\n\nimport { createElement, Fragment } from 'react';\n\nexport interface BreadcrumbItem {\n name: string;\n url?: string;\n}\n\nexport interface BreadcrumbProps {\n /** Breadcrumb items from root to current page */\n items: BreadcrumbItem[];\n /** Separator between items (default: \" / \") */\n separator?: string;\n /** CSS class for the nav element */\n className?: string;\n /** CSS class for each link */\n linkClassName?: string;\n /** CSS class for the current (last) item */\n activeClassName?: string;\n /** Whether to render the JSON-LD alongside the visual breadcrumb (default: true) */\n includeJsonLd?: boolean;\n}\n\n/**\n * Visual breadcrumb navigation with optional BreadcrumbList JSON-LD.\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * items={[\n * { name: 'Home', url: '/' },\n * { name: 'Blog', url: '/blog' },\n * { name: 'Current Post' },\n * ]}\n * />\n * ```\n */\nexport function Breadcrumb({\n items,\n separator = ' / ',\n className,\n linkClassName,\n activeClassName,\n includeJsonLd = true,\n}: BreadcrumbProps) {\n // Build JSON-LD schema\n const jsonLdData = {\n '@context': 'https://schema.org' as const,\n '@type': 'BreadcrumbList' as const,\n itemListElement: items.map((item, index) => ({\n '@type': 'ListItem' as const,\n position: index + 1,\n name: item.name,\n ...(item.url ? { item: item.url } : {}),\n })),\n };\n\n const children: ReturnType<typeof createElement>[] = [];\n\n // Render visual breadcrumb\n const breadcrumbItems: ReturnType<typeof createElement>[] = [];\n items.forEach((item, index) => {\n if (index > 0) {\n breadcrumbItems.push(\n createElement('span', { key: `sep-${index}`, 'aria-hidden': 'true' }, separator),\n );\n }\n\n const isLast = index === items.length - 1;\n\n if (item.url && !isLast) {\n breadcrumbItems.push(\n createElement(\n 'a',\n { key: `item-${index}`, href: item.url, className: linkClassName },\n item.name,\n ),\n );\n } else {\n breadcrumbItems.push(\n createElement(\n 'span',\n {\n key: `item-${index}`,\n className: isLast ? activeClassName : undefined,\n 'aria-current': isLast ? 'page' : undefined,\n },\n item.name,\n ),\n );\n }\n });\n\n children.push(\n createElement(\n 'nav',\n { 'aria-label': 'Breadcrumb', className },\n createElement(\n 'ol',\n {\n style: {\n listStyle: 'none',\n padding: 0,\n margin: 0,\n display: 'flex',\n flexWrap: 'wrap' as const,\n },\n },\n ...breadcrumbItems,\n ),\n ),\n );\n\n // Render JSON-LD\n if (includeJsonLd) {\n children.push(\n createElement('script', {\n key: 'breadcrumb-jsonld',\n type: 'application/ld+json',\n dangerouslySetInnerHTML: { __html: JSON.stringify(jsonLdData) },\n }),\n );\n }\n\n return createElement(Fragment, null, ...children);\n}\n"]} |
+1
-1
| { | ||
| "name": "@power-seo/react", | ||
| "version": "1.0.1", | ||
| "version": "1.0.2", | ||
| "description": "Framework-agnostic React SEO components — meta tags, Open Graph, Twitter Card, breadcrumbs, and more", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
95746
0.72%654
3.81%