From 2b173279539992574b5ef85a72d02fe3f0b601fa Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Fri, 16 Jun 2023 12:59:52 -1000 Subject: [PATCH] fix(PrismicImage): allow removing Imgix params in React Server Components using `null` (#188) --- src/PrismicImage.tsx | 32 +++++++++++++++++++------------- test/PrismicImage.test.tsx | 30 ++++++++++++++++++++++++++++++ test/__testutils__/renderJSON.ts | 4 ++-- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/PrismicImage.tsx b/src/PrismicImage.tsx index 4096cff..4d34aec 100644 --- a/src/PrismicImage.tsx +++ b/src/PrismicImage.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import * as prismic from "@prismicio/client"; +import { ImgixURLParams } from "imgix-url-builder"; import { devMsg } from "./lib/devMsg"; @@ -23,7 +24,7 @@ export type PrismicImageProps = Omit< * * See: https://docs.imgix.com/apis/rendering */ - imgixParams?: Parameters[1]; + imgixParams?: { [P in keyof ImgixURLParams]: ImgixURLParams[P] | null }; /** * Declare an image as decorative by providing `alt=""`. @@ -103,24 +104,22 @@ export type PrismicImageProps = Omit< * @returns A responsive image component for the given Image field. */ export const PrismicImage = React.forwardRef(function PrismicImage( - props: PrismicImageProps, - ref: React.ForwardedRef, -): JSX.Element | null { - const { + { field, alt, fallbackAlt, - imgixParams, + imgixParams = {}, widths, pixelDensities, ...restProps - } = props; - + }: PrismicImageProps, + ref: React.ForwardedRef, +): JSX.Element | null { if ( typeof process !== "undefined" && process.env.NODE_ENV === "development" ) { - if (typeof alt === "string" && props.alt !== "") { + if (typeof alt === "string" && alt !== "") { console.warn( `[PrismicImage] The "alt" prop can only be used to declare an image as decorative by passing an empty string (alt="") but was provided a non-empty string. You can resolve this warning by removing the "alt" prop or changing it to alt="". For more details, see ${devMsg( "alt-must-be-an-empty-string", @@ -144,23 +143,30 @@ export const PrismicImage = React.forwardRef(function PrismicImage( } if (prismic.isFilled.imageThumbnail(field)) { + const resolvedImgixParams = imgixParams; + for (const x in imgixParams) { + if (resolvedImgixParams[x as keyof typeof resolvedImgixParams] === null) { + resolvedImgixParams[x as keyof typeof resolvedImgixParams] = undefined; + } + } + let src: string | undefined; let srcSet: string | undefined; if (widths || !pixelDensities) { const res = prismic.asImageWidthSrcSet(field, { - ...imgixParams, + ...resolvedImgixParams, widths: widths === "defaults" ? undefined : widths, - }); + } as ImgixURLParams); src = res.src; srcSet = res.srcset; } else if (pixelDensities) { const res = prismic.asImagePixelDensitySrcSet(field, { - ...imgixParams, + ...resolvedImgixParams, pixelDensities: pixelDensities === "defaults" ? undefined : pixelDensities, - }); + } as ImgixURLParams); src = res.src; srcSet = res.srcset; diff --git a/test/PrismicImage.test.tsx b/test/PrismicImage.test.tsx index 49294f0..ee5dab9 100644 --- a/test/PrismicImage.test.tsx +++ b/test/PrismicImage.test.tsx @@ -323,3 +323,33 @@ it("supports imgix parameters", async (ctx) => { expect(actual).toStrictEqual(expected); }); + +it("allows removing existing Imgix params via the imgixParams prop", async (ctx) => { + const field = ctx.mock.value.image({ + model: ctx.mock.model.image(), + }); + const fieldURL = new URL(field.url); + fieldURL.searchParams.set("auto", "compress,format"); + fieldURL.searchParams.set("sat", "-100"); + fieldURL.searchParams.set("ar", "1:2"); + field.url = fieldURL.toString(); + + const img = renderJSON( + , + ); + + const src = new URL(img?.props.src); + + expect(src.searchParams.get("auto")).toBe(null); + expect(src.searchParams.get("sat")).toBe(null); + expect(src.searchParams.get("ar")).toBe("1:2"); +}); diff --git a/test/__testutils__/renderJSON.ts b/test/__testutils__/renderJSON.ts index 06bc2e1..18d538a 100644 --- a/test/__testutils__/renderJSON.ts +++ b/test/__testutils__/renderJSON.ts @@ -11,7 +11,7 @@ import * as renderer from "react-test-renderer"; export const renderJSON = ( element: React.ReactElement, options?: renderer.TestRendererOptions, -): renderer.ReactTestRendererJSON | renderer.ReactTestRendererJSON[] | null => { +): renderer.ReactTestRendererJSON | null => { let root: renderer.ReactTestRenderer; renderer.act(() => { @@ -19,5 +19,5 @@ export const renderJSON = ( }); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return root!.toJSON(); + return root!.toJSON() as renderer.ReactTestRendererJSON; };