wpheadless-lib 1.1.17 → 1.1.19

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.
@@ -0,0 +1,4 @@
1
+ declare const IntentLink: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").AnchorHTMLAttributes<HTMLAnchorElement>, keyof import("next/link").LinkProps<any>> & import("next/link").LinkProps<any> & {
2
+ children?: React.ReactNode | undefined;
3
+ } & import("react").RefAttributes<HTMLAnchorElement>, "ref"> & import("react").RefAttributes<HTMLAnchorElement>>;
4
+ export default IntentLink;
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import Link from "next/link";
4
+ import { useRouter } from "next/navigation";
5
+ import { forwardRef, useRef, } from "react";
6
+ function formatHref(href) {
7
+ if (typeof href === "string")
8
+ return href;
9
+ const pathname = href.pathname ?? "";
10
+ const search = href.search
11
+ ? href.search.startsWith("?")
12
+ ? href.search
13
+ : `?${href.search}`
14
+ : "";
15
+ const hash = href.hash
16
+ ? href.hash.startsWith("#")
17
+ ? href.hash
18
+ : `#${href.hash}`
19
+ : "";
20
+ return `${pathname}${search}${hash}`;
21
+ }
22
+ function isInternalHref(href) {
23
+ return href.startsWith("/") && !href.startsWith("//");
24
+ }
25
+ const IntentLink = forwardRef(function IntentLink({ href, onMouseEnter, onFocus, prefetch: _prefetch, ...props }, ref) {
26
+ const router = useRouter();
27
+ const lastPrefetchedHref = useRef(null);
28
+ const prefetchOnIntent = () => {
29
+ const formattedHref = formatHref(href);
30
+ if (!isInternalHref(formattedHref) ||
31
+ lastPrefetchedHref.current === formattedHref) {
32
+ return;
33
+ }
34
+ lastPrefetchedHref.current = formattedHref;
35
+ router.prefetch(formattedHref);
36
+ };
37
+ const handleMouseEnter = (event) => {
38
+ onMouseEnter?.(event);
39
+ if (!event.defaultPrevented)
40
+ prefetchOnIntent();
41
+ };
42
+ const handleFocus = (event) => {
43
+ onFocus?.(event);
44
+ if (!event.defaultPrevented)
45
+ prefetchOnIntent();
46
+ };
47
+ return (_jsx(Link, { ref: ref, ...props, href: href, prefetch: false, onMouseEnter: handleMouseEnter, onFocus: handleFocus }));
48
+ });
49
+ export default IntentLink;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Link from "next/link";
2
+ import IntentLink from "../IntentLink/index.js";
3
3
  import styles from "./index.module.css";
4
4
  import { getTranslator } from "../../utils/index.js";
5
5
  export function LanguageLinks({ links, label, locale, className, }) {
@@ -8,5 +8,5 @@ export function LanguageLinks({ links, label, locale, className, }) {
8
8
  return null;
9
9
  const t = getTranslator(locale);
10
10
  const resolvedLabel = label ?? t("language.available");
11
- return (_jsxs("nav", { "aria-label": resolvedLabel, className: [styles.languageLinks, className].filter(Boolean).join(" "), children: [_jsx("span", { className: styles.label, children: resolvedLabel }), _jsx("ul", { className: styles.list, children: visibleLinks.map((link) => (_jsx("li", { children: link.current ? (_jsx("span", { className: `${styles.link} ${styles.current}`, "aria-current": "page", lang: link.code, children: link.label })) : (_jsx(Link, { href: link.href, className: styles.link, hrefLang: link.code, children: link.label })) }, link.code))) })] }));
11
+ return (_jsxs("nav", { "aria-label": resolvedLabel, className: [styles.languageLinks, className].filter(Boolean).join(" "), children: [_jsx("span", { className: styles.label, children: resolvedLabel }), _jsx("ul", { className: styles.list, children: visibleLinks.map((link) => (_jsx("li", { children: link.current ? (_jsx("span", { className: `${styles.link} ${styles.current}`, "aria-current": "page", lang: link.code, children: link.label })) : (_jsx(IntentLink, { href: link.href, className: styles.link, hrefLang: link.code, children: link.label })) }, link.code))) })] }));
12
12
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Image from "next/image";
3
- import Link from "next/link";
3
+ import IntentLink from "../IntentLink/index.js";
4
4
  import { getFeaturedMedia } from "../../utils/index.js";
5
5
  import { buildCategoryUrl, buildPostUrl, formatPostDate, resolveCategorySlug, } from "./index.utils.js";
6
6
  import styles from "./index.module.css";
@@ -21,7 +21,7 @@ export default function PostCard({ post, categorySlug, locale = "en", defaultLoc
21
21
  defaultLocale,
22
22
  basePath,
23
23
  });
24
- return (_jsxs(Card, { as: "article", className: styles.card, children: [imageUrl && (_jsx(Link, { href: postUrl, className: styles.imageLink, children: _jsx("div", { className: styles.imageWrapper, children: _jsx(Image, { src: imageUrl, alt: featuredMedia?.alt_text || post.title.rendered, fill: true, style: { objectFit: "cover" }, sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" }) }) })), _jsxs(CardContent, { className: styles.body, children: [categories.length > 0 && (_jsx("div", { className: styles.badges, children: categories.map((cat) => (_jsx(Link, { href: buildCategoryUrl(cat.slug, locale, basePath, defaultLocale), className: badgeClassName(styles.badge), title: cat.name, children: truncateText(cat.name, 20) }, cat.id ?? cat.slug))) })), _jsxs(Link, { href: postUrl, className: styles.postLink, children: [_jsx("h2", { className: styles.title, dangerouslySetInnerHTML: {
24
+ return (_jsxs(Card, { as: "article", className: styles.card, children: [imageUrl && (_jsx(IntentLink, { href: postUrl, className: styles.imageLink, children: _jsx("div", { className: styles.imageWrapper, children: _jsx(Image, { src: imageUrl, alt: featuredMedia?.alt_text || post.title.rendered, fill: true, style: { objectFit: "cover" }, sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" }) }) })), _jsxs(CardContent, { className: styles.body, children: [categories.length > 0 && (_jsx("div", { className: styles.badges, children: categories.map((cat) => (_jsx(IntentLink, { href: buildCategoryUrl(cat.slug, locale, basePath, defaultLocale), className: badgeClassName(styles.badge), title: cat.name, children: truncateText(cat.name, 20) }, cat.id ?? cat.slug))) })), _jsxs(IntentLink, { href: postUrl, className: styles.postLink, children: [_jsx("h2", { className: styles.title, dangerouslySetInnerHTML: {
25
25
  __html: post.title.rendered,
26
26
  } }), _jsx("div", { dangerouslySetInnerHTML: {
27
27
  __html: post.excerpt.rendered,
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Link from "next/link";
2
+ import IntentLink from "../../IntentLink/index.js";
3
3
  import { getTranslator } from "../../../utils/index.js";
4
4
  import { fetchMenuLinks } from "../../../api/menus.js";
5
5
  import styles from "./index.module.css";
@@ -27,7 +27,7 @@ export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPasswo
27
27
  catch (e) {
28
28
  console.error("Error obteniendo menú footer:", e);
29
29
  }
30
- return (_jsx("footer", { className: styles.footer, children: _jsx("div", { className: styles.container, children: _jsxs("div", { className: styles.wrapper, children: [_jsxs("div", { className: styles.grid, children: [_jsxs("div", { children: [_jsx("div", { className: styles.siteName, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height, style: logoStyle })) : (siteName) }), _jsx("p", { className: `${styles.muted} text-muted`, children: t("footer.tagline") })] }), menuLinks.length > 0 && (_jsxs("nav", { "aria-label": t("footer.navAria"), className: styles.nav, children: [_jsx("h4", { className: styles.navTitle, children: t("footer.navTitle") }), _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(Link, { href: item.href, className: styles.footerLink, target: item.target || undefined, rel: item.target === "_blank"
30
+ return (_jsx("footer", { className: styles.footer, children: _jsx("div", { className: styles.container, children: _jsxs("div", { className: styles.wrapper, children: [_jsxs("div", { className: styles.grid, children: [_jsxs("div", { children: [_jsx("div", { className: styles.siteName, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height, style: logoStyle })) : (siteName) }), _jsx("p", { className: `${styles.muted} text-muted`, children: t("footer.tagline") })] }), menuLinks.length > 0 && (_jsxs("nav", { "aria-label": t("footer.navAria"), className: styles.nav, children: [_jsx("h4", { className: styles.navTitle, children: t("footer.navTitle") }), _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(IntentLink, { href: item.href, className: styles.footerLink, target: item.target || undefined, rel: item.target === "_blank"
31
31
  ? "noopener noreferrer"
32
32
  : undefined, children: item.label }) }, item.id))) })] }))] }), _jsxs("div", { className: styles.bottomBar, children: [_jsxs("span", { children: ["\u00A9 ", new Date().getFullYear(), " ", siteName] }), _jsx("span", { children: t("footer.noCookies") })] })] }) }) }));
33
33
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import Link from "next/link";
3
+ import IntentLink from "../../IntentLink/index.js";
4
4
  import { useEffect, useRef, useState } from "react";
5
5
  import styles from "./index.module.css";
6
6
  import { Button } from "../../ui/index.js";
@@ -49,7 +49,7 @@ export default function HeaderClient({ menuLinks, siteName, homeHref, labels, lo
49
49
  ...(logoData.width ? { width: logoData.width } : {}),
50
50
  }
51
51
  : undefined;
52
- return (_jsxs("div", { className: styles.inner, children: [_jsx(Link, { href: homeHref, className: styles.logo, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height, style: logoStyle })) : (siteName) }), menuLinks.length > 0 && (_jsxs("div", { className: styles.navWrapper, children: [_jsxs(Button, { type: "button", variant: "ghost", className: styles.menuButton, ref: menuButtonRef, "aria-expanded": isMenuOpen, "aria-controls": "primary-navigation", "aria-label": menuLabel, onClick: toggleMenu, children: [_jsxs("span", { className: styles.menuIcon, "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { className: styles.menuText, children: menuLabel })] }), _jsx("nav", { id: "primary-navigation", ref: navRef, "aria-label": labels.navAria, className: `${styles.nav} ${isMenuOpen ? styles.navOpen : ""}`, "aria-hidden": !isMenuOpen && isMobileView, hidden: !isMenuOpen && isMobileView, children: _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(Link, { href: item.href, className: styles.navLink, onClick: handleLinkClick, tabIndex: !isMenuOpen && isMobileView ? -1 : undefined, target: item.target || undefined, rel: item.target === "_blank"
52
+ return (_jsxs("div", { className: styles.inner, children: [_jsx(IntentLink, { href: homeHref, className: styles.logo, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height, style: logoStyle })) : (siteName) }), menuLinks.length > 0 && (_jsxs("div", { className: styles.navWrapper, children: [_jsxs(Button, { type: "button", variant: "ghost", className: styles.menuButton, ref: menuButtonRef, "aria-expanded": isMenuOpen, "aria-controls": "primary-navigation", "aria-label": menuLabel, onClick: toggleMenu, children: [_jsxs("span", { className: styles.menuIcon, "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { className: styles.menuText, children: menuLabel })] }), _jsx("nav", { id: "primary-navigation", ref: navRef, "aria-label": labels.navAria, className: `${styles.nav} ${isMenuOpen ? styles.navOpen : ""}`, "aria-hidden": !isMenuOpen && isMobileView, hidden: !isMenuOpen && isMobileView, children: _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(IntentLink, { href: item.href, className: styles.navLink, onClick: handleLinkClick, tabIndex: !isMenuOpen && isMobileView ? -1 : undefined, target: item.target || undefined, rel: item.target === "_blank"
53
53
  ? "noopener noreferrer"
54
54
  : undefined, children: item.label }) }, item.id))) }) })] }))] }));
55
55
  }
@@ -1,8 +1,8 @@
1
- import Link from "next/link";
1
+ import IntentLink from "../IntentLink/index.js";
2
2
  import type { ComponentPropsWithoutRef } from "react";
3
3
  export declare function Breadcrumb({ className, ...props }: ComponentPropsWithoutRef<"nav">): import("react").JSX.Element;
4
4
  export declare function BreadcrumbList({ className, ...props }: ComponentPropsWithoutRef<"ol">): import("react").JSX.Element;
5
5
  export declare function BreadcrumbItem({ className, ...props }: ComponentPropsWithoutRef<"li">): import("react").JSX.Element;
6
- export declare function BreadcrumbLink({ className, ...props }: ComponentPropsWithoutRef<typeof Link>): import("react").JSX.Element;
6
+ export declare function BreadcrumbLink({ className, ...props }: ComponentPropsWithoutRef<typeof IntentLink>): import("react").JSX.Element;
7
7
  export declare function BreadcrumbPage({ className, ...props }: ComponentPropsWithoutRef<"span">): import("react").JSX.Element;
8
8
  export declare function BreadcrumbSeparator({ className, children, ...props }: ComponentPropsWithoutRef<"span">): import("react").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import Link from "next/link";
2
+ import IntentLink from "../IntentLink/index.js";
3
3
  import { cn } from "./cn.js";
4
4
  import styles from "./breadcrumb.module.css";
5
5
  export function Breadcrumb({ className, ...props }) {
@@ -12,7 +12,7 @@ export function BreadcrumbItem({ className, ...props }) {
12
12
  return (_jsx("li", { "data-slot": "breadcrumb-item", className: cn(styles.item, className), ...props }));
13
13
  }
14
14
  export function BreadcrumbLink({ className, ...props }) {
15
- return (_jsx(Link, { "data-slot": "breadcrumb-link", className: cn(styles.link, className), ...props }));
15
+ return (_jsx(IntentLink, { "data-slot": "breadcrumb-link", className: cn(styles.link, className), ...props }));
16
16
  }
17
17
  export function BreadcrumbPage({ className, ...props }) {
18
18
  return (_jsx("span", { "data-slot": "breadcrumb-page", "aria-current": "page", className: cn(styles.page, className), ...props }));
@@ -1,9 +1,9 @@
1
- import Link from "next/link";
1
+ import IntentLink from "../IntentLink/index.js";
2
2
  import type { ComponentPropsWithoutRef } from "react";
3
3
  export declare function Pagination({ className, ...props }: ComponentPropsWithoutRef<"nav">): import("react").JSX.Element;
4
4
  export declare function PaginationContent({ className, ...props }: ComponentPropsWithoutRef<"ul">): import("react").JSX.Element;
5
5
  export declare function PaginationItem(props: ComponentPropsWithoutRef<"li">): import("react").JSX.Element;
6
- type PaginationLinkProps = ComponentPropsWithoutRef<typeof Link> & {
6
+ type PaginationLinkProps = ComponentPropsWithoutRef<typeof IntentLink> & {
7
7
  isActive?: boolean;
8
8
  size?: "default" | "icon";
9
9
  };
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Link from "next/link";
2
+ import IntentLink from "../IntentLink/index.js";
3
3
  import { cn } from "./cn.js";
4
4
  import styles from "./pagination.module.css";
5
5
  export function Pagination({ className, ...props }) {
@@ -12,7 +12,7 @@ export function PaginationItem(props) {
12
12
  return _jsx("li", { "data-slot": "pagination-item", ...props });
13
13
  }
14
14
  export function PaginationLink({ className, isActive, size = "icon", ...props }) {
15
- return (_jsx(Link, { "data-slot": "pagination-link", "data-active": isActive, "aria-current": isActive ? "page" : undefined, className: cn(styles.link, size === "icon" ? styles.icon : styles.defaultSize, isActive && styles.active, className), ...props }));
15
+ return (_jsx(IntentLink, { "data-slot": "pagination-link", "data-active": isActive, "aria-current": isActive ? "page" : undefined, className: cn(styles.link, size === "icon" ? styles.icon : styles.defaultSize, isActive && styles.active, className), ...props }));
16
16
  }
17
17
  export function PaginationPrevious({ children, className, ...props }) {
18
18
  return (_jsxs(PaginationLink, { size: "default", className: className, ...props, children: [_jsx("span", { "aria-hidden": "true", children: "\u2190" }), _jsx("span", { children: children })] }));
@@ -34,6 +34,7 @@ type RewriteOpts = {
34
34
  wpApiUrl?: string;
35
35
  basePath?: string;
36
36
  inLanguage?: string;
37
+ canonicalUrl?: string;
37
38
  };
38
39
  /**
39
40
  * Replace Yoast URLs so they match the frontend domain instead of the WP API domain.
package/dist/utils/seo.js CHANGED
@@ -110,6 +110,47 @@ const rewriteYoastSchemaUrls = (schema, opts, canonical) => {
110
110
  return schema;
111
111
  return rewriteSchemaValue(schema, origins);
112
112
  };
113
+ const applyCanonicalUrlOverride = (schema, canonicalUrl) => {
114
+ if (!canonicalUrl || !schema || typeof schema !== "object")
115
+ return schema;
116
+ const graph = schema["@graph"];
117
+ if (!Array.isArray(graph))
118
+ return schema;
119
+ const pageUrls = new Set();
120
+ for (const node of graph) {
121
+ if (!nodeHasType(node, "WebPage"))
122
+ continue;
123
+ if (typeof node["@id"] === "string")
124
+ pageUrls.add(node["@id"]);
125
+ if (typeof node.url === "string")
126
+ pageUrls.add(node.url);
127
+ }
128
+ if (!pageUrls.size)
129
+ return schema;
130
+ const replacePageReferences = (value) => {
131
+ if (typeof value === "string") {
132
+ return pageUrls.has(value) ? canonicalUrl : value;
133
+ }
134
+ if (Array.isArray(value))
135
+ return value.map(replacePageReferences);
136
+ if (value && typeof value === "object") {
137
+ return Object.fromEntries(Object.entries(value).map(([key, val]) => [
138
+ key,
139
+ replacePageReferences(val),
140
+ ]));
141
+ }
142
+ return value;
143
+ };
144
+ const normalizedGraph = graph.map((node) => {
145
+ const next = replacePageReferences(node);
146
+ if (nodeHasType(next, "WebPage")) {
147
+ next["@id"] = canonicalUrl;
148
+ next.url = canonicalUrl;
149
+ }
150
+ return next;
151
+ });
152
+ return { ...schema, "@graph": normalizedGraph };
153
+ };
113
154
  const getYoastDescription = (yoast) => {
114
155
  const description = yoast?.description || yoast?.og_description;
115
156
  return typeof description === "string" && description.trim()
@@ -256,7 +297,8 @@ export function getYoastSchema(entity, opts) {
256
297
  return null;
257
298
  const options = opts ?? {};
258
299
  const enriched = enrichYoastSchema(yoast.schema, entity, yoast, options);
259
- return rewriteYoastSchemaUrls(enriched, options, yoast.canonical) || null;
300
+ const rewritten = rewriteYoastSchemaUrls(enriched, options, yoast.canonical);
301
+ return applyCanonicalUrlOverride(rewritten, options.canonicalUrl) || null;
260
302
  }
261
303
  export function stripBreadcrumbsFromSchema(schema) {
262
304
  if (!schema || typeof schema !== "object")
@@ -1,6 +1,6 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import Image from "next/image";
3
- import Link from "next/link";
3
+ import IntentLink from "../../components/IntentLink/index.js";
4
4
  import Paginator from "../../components/Paginator/index.js";
5
5
  import PostCard from "../../components/PostCard/index.js";
6
6
  import styles from "./index.module.css";
@@ -19,7 +19,7 @@ export function HomeView({ featuredPost, regularPosts, error, totalPages, baseUr
19
19
  return (_jsx("div", { className: styles.container, children: error ? (_jsxs(Alert, { className: styles.errorBox, variant: "destructive", children: [_jsxs(AlertTitle, { children: [copy.errorTitle, ": ", error] }), _jsx(AlertDescription, { className: styles.errorHint, children: copy.errorHint })] })) : !featuredModel && regularPosts.length === 0 ? (_jsx("p", { className: styles.empty, children: copy.empty })) : (_jsxs(_Fragment, { children: [_jsx("h1", { id: "home-title", className: styles.visuallyHidden, children: copy.title }), _jsx("section", { className: styles.masthead, "aria-labelledby": "home-title", children: featuredModel && (_jsxs("article", { className: `${styles.featured} ${featuredModel.image
20
20
  ? styles.featuredWithImage
21
21
  : styles.featuredNoImage}`, children: [featuredModel.image && (_jsxs("div", { className: styles.featuredImageFrame, children: [_jsx(Image, { src: featuredModel.image.src, alt: featuredModel.image.alt, fill: true, className: styles.featuredImage, priority: true, sizes: "(max-width: 768px) 100vw, 50vw" }), _jsx("div", { className: styles.featuredOverlay, "aria-hidden": "true" })] })), _jsxs("div", { className: styles.featuredBody, children: [featuredModel.badgeLabel &&
22
- (featuredModel.badgeUrl ? (_jsx(Link, { href: featuredModel.badgeUrl, className: badgeClassName(styles.featuredBadge), title: featuredModel.badgeLabel, children: truncateLabel(featuredModel.badgeLabel) })) : (_jsx("span", { className: badgeClassName(styles.featuredBadge), title: featuredModel.badgeLabel, children: truncateLabel(featuredModel.badgeLabel) }))), _jsx(Link, { href: featuredModel.postUrl, children: _jsx("h2", { dangerouslySetInnerHTML: {
22
+ (featuredModel.badgeUrl ? (_jsx(IntentLink, { href: featuredModel.badgeUrl, className: badgeClassName(styles.featuredBadge), title: featuredModel.badgeLabel, children: truncateLabel(featuredModel.badgeLabel) })) : (_jsx("span", { className: badgeClassName(styles.featuredBadge), title: featuredModel.badgeLabel, children: truncateLabel(featuredModel.badgeLabel) }))), _jsx(IntentLink, { href: featuredModel.postUrl, children: _jsx("h2", { dangerouslySetInnerHTML: {
23
23
  __html: featuredModel.titleHtml,
24
24
  }, className: styles.featuredTitle }) }), _jsx("div", { dangerouslySetInnerHTML: {
25
25
  __html: featuredModel.excerptHtml,
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Image from "next/image";
3
- import Link from "next/link";
3
+ import IntentLink from "../../components/IntentLink/index.js";
4
4
  import styles from "./index.module.css";
5
5
  import { getTranslator, getYoastSchema, rewritePostContentLinks, stripBreadcrumbsFromSchema, } from "../../utils/index.js";
6
6
  import { Breadcrumbs, JsonLd, LanguageLinks } from "../../components/index.js";
@@ -42,5 +42,5 @@ export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", l
42
42
  inLanguage: dateLocale,
43
43
  }))
44
44
  : null;
45
- return (_jsxs("div", { className: styles.container, children: [_jsx(JsonLd, { data: yoastSchema }), _jsxs("article", { className: styles.article, children: [_jsx(Breadcrumbs, { items: breadcrumbs }), featuredImage && (_jsxs("figure", { className: styles.figure, children: [_jsx(Image, { src: featuredImage.src, alt: featuredImage.alt, fill: true, className: styles.image, priority: priorityImage, sizes: "(max-width: 1200px) 100vw, 1200px" }), _jsx("div", { className: styles.heroOverlay, "aria-hidden": "true" }), primaryCategory && (_jsx("div", { className: styles.badgeOverlay, children: categoryUrl ? (_jsx(Link, { href: categoryUrl, className: badgeClassName(), title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) : (_jsx("span", { className: badgeClassName(), title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) })), _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: `${styles.title} ${styles.heroTitle}` })] })), !featuredImage && (_jsx("header", { className: styles.postHeader, children: _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: styles.title }) })), _jsxs("div", { className: styles.meta, children: [author && (_jsx("span", { className: styles.authorLabel, children: t("post.authorPrefix", { name: author.name }) })), _jsx("span", { children: "\u2022" }), _jsx("time", { dateTime: post.date, children: publishedDate })] }), _jsx("div", { dangerouslySetInnerHTML: { __html: contentHtml }, className: `post-content ${styles.content}` }), disclaimer && (_jsx(Alert, { className: styles.disclaimer, role: "note", children: disclaimer })), _jsx(LanguageLinks, { links: languageLinks, locale: locale }), author && (_jsx(Card, { as: "aside", className: styles.authorCard, size: "sm", children: _jsx(CardContent, { children: _jsxs("address", { className: styles.authorAddress, children: [_jsx("strong", { className: styles.authorName, children: author.name }), authorBio && _jsx("p", { className: styles.authorBio, children: authorBio })] }) }) }))] })] }));
45
+ return (_jsxs("div", { className: styles.container, children: [_jsx(JsonLd, { data: yoastSchema }), _jsxs("article", { className: styles.article, children: [_jsx(Breadcrumbs, { items: breadcrumbs }), featuredImage && (_jsxs("figure", { className: styles.figure, children: [_jsx(Image, { src: featuredImage.src, alt: featuredImage.alt, fill: true, className: styles.image, priority: priorityImage, sizes: "(max-width: 1200px) 100vw, 1200px" }), _jsx("div", { className: styles.heroOverlay, "aria-hidden": "true" }), primaryCategory && (_jsx("div", { className: styles.badgeOverlay, children: categoryUrl ? (_jsx(IntentLink, { href: categoryUrl, className: badgeClassName(), title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) : (_jsx("span", { className: badgeClassName(), title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) })), _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: `${styles.title} ${styles.heroTitle}` })] })), !featuredImage && (_jsx("header", { className: styles.postHeader, children: _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: styles.title }) })), _jsxs("div", { className: styles.meta, children: [author && (_jsx("span", { className: styles.authorLabel, children: t("post.authorPrefix", { name: author.name }) })), _jsx("span", { children: "\u2022" }), _jsx("time", { dateTime: post.date, children: publishedDate })] }), _jsx("div", { dangerouslySetInnerHTML: { __html: contentHtml }, className: `post-content ${styles.content}` }), disclaimer && (_jsx(Alert, { className: styles.disclaimer, role: "note", children: disclaimer })), _jsx(LanguageLinks, { links: languageLinks, locale: locale }), author && (_jsx(Card, { as: "aside", className: styles.authorCard, size: "sm", children: _jsx(CardContent, { children: _jsxs("address", { className: styles.authorAddress, children: [_jsx("strong", { className: styles.authorName, children: author.name }), authorBio && _jsx("p", { className: styles.authorBio, children: authorBio })] }) }) }))] })] }));
46
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wpheadless-lib",
3
- "version": "1.1.17",
3
+ "version": "1.1.19",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,6 +9,7 @@
9
9
  "scripts": {
10
10
  "build": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json -f && node ./scripts/copy-assets.mjs",
11
11
  "copy:assets": "node ./scripts/copy-assets.mjs",
12
+ "test": "vitest run",
12
13
  "prepublishOnly": "npm run build"
13
14
  },
14
15
  "files": [
@@ -62,14 +63,17 @@
62
63
  "wpjsapi-lib": "^3.1.2"
63
64
  },
64
65
  "devDependencies": {
66
+ "@testing-library/react": "^16.3.2",
65
67
  "@types/node": "^20",
66
68
  "@types/react": "^19",
67
69
  "@types/react-dom": "^19",
70
+ "jsdom": "^26.1.0",
68
71
  "next": "16.2.6",
69
72
  "react": "19.2.6",
70
73
  "react-dom": "19.2.6",
71
74
  "tsc-alias": "^1.8.10",
72
- "typescript": "^5.9.3"
75
+ "typescript": "^5.9.3",
76
+ "vitest": "^4.1.10"
73
77
  },
74
78
  "peerDependencies": {
75
79
  "next": "^16.2.6",