Coder Social home page Coder Social logo

prismicio / prismic-helpers Goto Github PK

View Code? Open in Web Editor NEW
15.0 18.0 9.0 1.36 MB

Set of helpers to manage Prismic data

Home Page: https://prismic.io/docs/technical-reference/prismicio-helpers

License: Apache License 2.0

JavaScript 1.54% TypeScript 98.46%
prismic javascript typescript

prismic-helpers's Introduction

Note: This package has been merged into @prismicio/client ≥ v7.

This package and repository will no longer be updated, except in special circumstances.

@prismicio/helpers

npm version npm downloads Github Actions CI Codecov Conventional Commits License

Set of helpers to manage Prismic data.

  • 📅  Transform Date and Timestamp fields into Date objects;
  • 🗺  Resolve any kind of Link fields;
  • 🌐  Dedicated GraphQL API support.

Install

npm install @prismicio/helpers

Documentation

To discover what's new on this package check out the changelog. For full documentation, visit the official Prismic documentation.

Contributing

Whether you're helping us fix bugs, improve the docs, or spread the word, we'd love to have you as part of the Prismic developer community!

Asking a question: Open a new topic on our community forum explaining what you want to achieve / your question. Our support team will get back to you shortly.

Reporting a bug: Open an issue explaining your application's setup and the bug you're encountering.

Suggesting an improvement: Open an issue explaining your improvement or feature so we can discuss and learn more.

Submitting code changes: For small fixes, feel free to open a pull request with a description of your changes. For large changes, please first open an issue so we can discuss if and how the changes should be implemented.

For more clarity on this project and its structure you can also check out the detailed CONTRIBUTING.md document.

License

   Copyright 2013-2022 Prismic <[email protected]> (https://prismic.io)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

prismic-helpers's People

Contributors

angeloashmore avatar arnaudlewis avatar hypervillain avatar lihbr avatar srenault avatar tornqvist avatar trysound avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prismic-helpers's Issues

Link resolver should be optional in `asLink`, `asHTML`

A Link Resolver function is currently required in asLink and asHTML.

A Link Resolver should be optional instead since users may use Route Resolvers to populate a document or link's url field. In those cases, a Link Resolver would be unnecessary.

When a Link Resolver is not provided, it should fallback to field.url. This is what v1 does:

if (
link &&
[link.type, link.link_type, link._linkType, link.linkType].some(
e => e && ["Document", "Link.Document", "Link.document"].includes(e)
) && linkResolver && typeof linkResolver === 'function'
) {
const url = linkResolver(doc)
if (url) {
return url
}
}
if (doc && doc.url) {
return doc.url;
}

Support nullish inputs for `isFilled` helpers

Is your feature request related to a problem? Please describe.

The isFilled helpers currently require a non-nullish input to detect if its is filled or not. This requires extra code when the input may be nullish (such as documents that have not yet loaded).

Note the need to check if slice.primary.text?.richText is truthy in the following example.

export default function TextSlice({ slice }: SliceComponentProps<PrismicText>) {
	return (
		<section>
			{slice.primary.text?.richText &&
				isFilled.richText(slice.primary.text.richText) && (
					<div>
						<PrismicRichText field={slice.primary.text.richText} />
					</div>
				)}
		</section>
	);
}

Describe the solution you'd like

The isFilled helpers could accept null or undefined values. This removes the need to manually check if the field is present.

export default function TextSlice({ slice }: SliceComponentProps<PrismicText>) {
	return (
		<section>
			{isFilled.richText(slice.primary.text?.richText) && (
				<div>
					<PrismicRichText field={slice.primary.text?.richText} />
				</div>
			)}
		</section>
	);
}

Describe alternatives you've considered

The alternative is provided as an example in the first section.

Additional context

N/A

`prismicH.asImageSrc` using `width` instead of `w` doesn't do anything

Versions

  • @prismicio/helpers: ^2.3.9
  • node: v16.17.1

Steps to reproduce

  const imgSrc = prismicH.asImageSrc(images[0]?.image, {
    width: 250, // does not work
    height: 250, // does not work
    q: 75,
    fm: "webp",
    fit: "crop",
  });

  const imgSrc = prismicH.asImageSrc(images[0]?.image, {
    w: 250, // works
    h: 250, // works
    q: 75,
    fm: "webp",
    fit: "crop",
  });

What is expected?

Using the param width and height optimize the image

What is actually happening?

The param width and height have no effect

Add `documentAsLink` convenience function

A documentAsLink convenience function could be a more ergonomic way to convert a full Prismic document to a URL.

A user currently needs to perform the following steps to get a document's URL in a type-safe way:

import * as prismicH from '@prismicio/helpers'

const url = prismicH.asLink(
  prismicH.documentToLinkField(document),
  linkResolver,
)

Since this may be a common use case, we could simplify it to the following:

import * as prismicH from '@prismicio/helpers'

const url = prismicH.documentAsLink(document, linkResolver)

The implementation could be as simple as composing asLink and documentToLinkField:

import * as prismicH from "@prismicio/helpers";
import * as prismicT from "@prismicio/types";

export const documentAsLink = <TDocument extends prismicT.PrismicDocument>(
	document: TDocument,
	linkResolver: prismicH.LinkResolverFunction,
): string | null =>
	prismicH.asLink(prismicH.documentToLinkField(document), linkResolver);

.asHtml not recognized in prismicH.asHtml (using Vite, Vue 3 and Nuxt 3)

Hello, I'm having an issue while implementing prismic-helpers in replacement of old prismic-dom library.
Also I wanted to check if it is compatible with Vite and Nuxt 3, because after implementing all the changes I'm having

[nuxt] [request error] [unhandled] [500] vite_ssr_import_0.asHtml is not a function
at Proxy.dynamicComponent (./src/components/content/PrismicField.vue:47:48)
at ReactiveEffect.run (./node_modules/@vue/reactivity/dist/reactivity.cjs.js:162:19)
at get value [as value] (./node_modules/@vue/reactivity/dist/reactivity.cjs.js:1131:33)
at Object.get [as dynamicComponent] (./node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3410:22)
at _sfc_ssrRender (./src/components/content/PrismicField.vue:89:136)
at renderComponentSubTree (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:683:9)
at renderComponentVNode (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:631:12)
at renderVNode (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:743:14)
at renderVNodeChildren (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:759:5)
at renderElementVNode (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:806:9)

when I try to call this method the new way :

       ${prismicH.asHtml(
           this.field,
           // null param because this prismic function need normaly a link-resolver param
           // doc : https://prismic.io/docs/javascript/templating/rich-text
           // but we put the link-resolver in the back-end so we do no longer need link-resolver in front
           null,
           htmlSerializer
      )}</div>`,
      
      I have the import here in the vue file 
      import * as prismicH from '@prismicio/helpers';
      
      and I also have the htmlSerializer defined in another file.
      
      But the error comes right away when calling prismicH.asHtml.
      
      What should I do ?
      


PS: Package.json is like this :
      
"devDependencies": {
      "@nuxt/devtools": "latest",
      "nuxt": "^3.8.1",
      "sass": "^1.69.5",
      "sass-loader": "^13.3.2",
      "vue": "^3.3.8",
      "vue-router": "^4.2.5"
  },
"dependencies": {
      "@bootstrap-vue-next/nuxt": "^0.14.10",
      "@nuxtjs/i18n": "^8.0.0-rc.5",
      "@pinia/nuxt": "^0.5.1",
      "@popperjs/core": "^2.11.8",
      "@prismicio/helpers": "^2.3.9",
      "bootstrap": "^5.3.2",
      "bootstrap-vue-next": "^0.14.10",
      "nuxt-jsonld": "^2.0.8",
      "vite-svg-loader": "^4.0.0"
}

V2 Incompatible with gatsby-source-prismic?

I'm encountering an issue with this package (version 2.0.0-beta.3) when using <PrismicLink/> from @prismicio/react .

When passing the document prop to the PrismicLink component like so

<PrismicLink document={doc}>
    Click Here
</PrismicLink>

I get the following error

image

slugs is not a valid field to query on a document type in gatsby-source-prismic so it isn't possible to just add this field to my query. This is also supported by this comment I found in the source code of this repo.

slug: prismicDocument.slugs[0], // Slug field is not available with GraphQl

Does this indicate that latest beta versions of @prismicio/react and its peer dependencies are not currently supported for use in Gatsby projects?

utility or cli to extract response type definition from prismic custom types

feature request description

prismic surrounds it’s schemas in custom-types a single json file can describe the whole project schema (retrievable from the custom types api, and also the same json can be used to port over this schemas into other prismic projects — using prismic themes or the custom types api aforementioned.

the missing piece to a sounder typescript experience would be to have a type utility that converts this same json (probably saved statically on the project) to output the response json type — we already have individual types for each field, but we need to keep both the prismic dashboard, the json file and the typescript definition for each custom-type in sync, so it’s not only extra burden, but error prone and harder to maintain

description (idea) for the solution

i would like to have a single type that inferred the whole shape for a custom type based on it’s custom-type content:

import { ExtractResponseFromCustomType } from '@prismicio/helpers'
import homepage from '/custom_types/homepage.json'

export type HomePageResponse = ExtractResponseFromCustomType<typeof homepage>
//          └── { _meta: { uid: string }, [...], body: { [...] } }

alternatives considered

  1. the described approach
  2. a script/cli that would generate the types based on the repository name and/or repository endpoint

Type error: '?' expected.

Versions

  • @prismicio/helpers: 2.3.2
  • node: v16.13.1
  • typescript: 4.5.4

Reproduction

I updated to 2.3.2 and when I run tsc I get this error:

./node_modules/@prismicio/helpers/dist/index.d.ts:399:2
Type error: '?' expected.

  397 |     embed_url: string;
  398 |     html: string | null;
> 399 | }) ? {
      |  ^
  400 |     [x: string]: never;
  401 | } | (Data & {
  402 |     embed_url: string;

Steps to reproduce

What is expected?

The build compiles

What is actually happening?

Failed to compile

Workaround

Use v2.3.1

Create a helper to transform html code in RichText object

Is your feature request related to a problem? Please describe.

Hey Guys,

I see the function prismicHelper.asHtml and i have an idea based on a workaround that i did on my team.

Currently on my team we have a tool to create prismic pages massively. We use a spreadsheet file (csv/excel) to create the fields of the prismic document and upload it to prismic via import/export feature.

e.g

title banner.title (RichTextField)
Title of the page <h1>Heading</h1>

So, we have a helper function that transform the given html(argmument) to a RichText field of prismic.

Describe the solution you'd like

I would like to have a helper on @prismic-helpers package to transform html code to RichText code.

Describe alternatives you've considered

Created my own helper.

[bug] `get()` doesn't accept single predicate

In v5, query() will accept a single predicate or an array of predicates. In v6, get() doesn't recognize a single predicate, and returns unfiltered results:

import * as prismic from '@prismicio/client';
import * as prismicH from '@prismicio/helpers';
import fetch from 'node-fetch';

const repoName = 'prismicio-docs-v3'
const endpoint = prismic.getEndpoint(repoName);
const client = prismic.createClient(endpoint, { fetch });

const init = async () => {
  const docs = await client.get(
    prismic.predicate.at('document.type', 'core_concepts_article')
  );
  console.log(docs.results[0]);
};

init();

RFC: Provide image URL helpers for Imgix's URL API

Overview

This RFC addresses a need for straightforward image manipulation using Prismic’s Imgix integration.

What and/or who is affected by this RFC?

This affects all Prismic users using JavaScript in their projects with images.

The @prismicio/helpers library is also affected by this RFC.

Libraries that use @prismicio/helpers, such as @prismicio/react and @prismicio/vue, may also be affected as a result of needing to provide new helpers, but are outside the scope of this RFC.

Why is this being proposed?

Most users are not aware of Imgix’s capabilities and are not taking advantage of it (no data to back this up; just a hypothesis). We can enable users to make full use of Imgix’s features by providing an easy to use API.

Background Information

What is the current situation?

Today, all users have access to Imgix image transformations for all images uploaded to their Prismic repositories. Transformations are performed via URL parameters. For example, an image can be resized to 400px wide with the w parameter:

https://images.prismic.io/qwerty/image.png?w=400

The Prismic documentation currently recommends using manual string manipulation.

Apply your own transformations

Because images are served through Imgix, you can add any other Imgix transformations that you like. Using string handling, remove, add, or modify the parameters in the URL.

const imageUrl = `https://images.prismic.io/slicemachine-blank/dcea6535-f43b-49a7-8623-bf281aaf1cb2_roller-skating.png?auto=compress,format&rect=255,0,1536,1536&w=500&h=500`
pixelizedImageUrl = imageUrl + `&px=10`
console.log(pixelizedImageUrl)

Source: https://prismic.io/docs/core-concepts/image#apply-your-own-transformations

Imgix provides a few libraries to make this process easier, such as @imgix/js-core and react-imgix. Rather than manipulating strings manually, a user can use these libraries to build URLs with a nicer API. For example:

const client = new ImgixClient({
  domain: 'testing.imgix.net',
});

const url = client.buildURL('folder/image.jpg', {
  w: 1000,
});
// => https://testing.imgix.net/folder/image.jpg?w=1000

What are the current problems?

String manipulation is fragile and requires users to know exactly how the end URL should appear. This is a leaky abstraction; a user must understand Imgix to make use of image transformations. A user must also be careful to craft a correct and valid URL.

When working with a CMS where editors can change content, including image URLs and the URL parameters attached to them, building custom image URLs by hand can quickly become frustrating.

The API for Imgix’s core library is awkward to use since it requires instantiating a client and manually separating the URL’s domain (testing.imgix.net) from the image’s path (folder/image.jpg). Prismic users should not have to care about this since images are always coming from images.prismic.io.

Imgix’s libraries are also relatively large and heavy since they need to support many different use cases. Prismic is typically used for public facing websites where library size is a strong consideration when deciding to integrate a feature. As a result, importing relatively large libraries for string manipulation is undesirable.

Are there any related discussions from elsewhere?

This proposal was sparked by a question from @samlfair. Repeated by @a-trost:

Sam brought up that the url that people get back from prismic for images already has certain things like compression baked in, so to change it they have to do some string manipulation. We walk them through this in the docs, but it's clearly not a great way to go about it. We have a lot of potential with imgix that I don't think most of our users are leveraging. I remember you were making an imgix-lite package for Gatsby before. What's the status with that? And might we want to create a helper or something for working with imgix images, mainly to hack around their SDKs being sub-optimal?

Proposal

Assume @prismicio/helpers is imported as prismicH in the following code blocks.

Applying image transformations should be as simple as a single function call to transformImageURL():

const url = prismicH.transformImageURL(document.data.myImage.url, {
  width: 400
})
// => https://images.prismic.io/my-repo-name/my-image.png?w=400&auto=format,compress

Removing parameters, such as auto (which is automatically applied to all Prismic images), should be straightforward as well:

const url = prismicH.transformImageURL(document.data.myImage.url, {
  auto: undefined
})
// => https://images.prismic.io/my-repo-name/my-image.png

Building responsive images using srcset with <img> could be generated with a function called buildImageSrcSet():

const srcset = prismicH.buildImageSrcSet(document.data.myImage.url, {
  sizes: [400, 800, 1600]
})
// => https://images.prismic.io/my-repo-name/my-image.png?w=400 400w,
//    https://images.prismic.io/my-repo-name/my-image.png?w=800 800w,
//    https://images.prismic.io/my-repo-name/my-image.png?w=1600 1600w

Similarly, building a srcset using display pixel densities instead could be generated with a function called buildImageDPRSrcSet() (DPR = device pixel ratio):

const srcset = prismicH.buildImageDPRSrcSet(document.data.myImage.url, {
  ratios: [1, 2, 3]
})
// => https://images.prismic.io/my-repo-name/my-image.png?dpr=1,
//    https://images.prismic.io/my-repo-name/my-image.png?dpr=2 2x,
//    https://images.prismic.io/my-repo-name/my-image.png?dpr=2 3x

As mentioned earlier, these helper functions could make their way into integration libraries like @prismicio/react and @prismicio/vue. Such an API requires more thought and discussion and is outside the scope of this proposal.

How it could be implemented

The core of the proposed functions is a simple URL manipulation function. It uses the native URL and URLSearchParams Web APIs to add, remove, and modify URL parameters.

// Assume ImgixURLParams is an interface of all Imgix parameters

export const buildURL = (url: string, params: ImgixURLParams): string => {
	const instance = new URL(url);

	for (const camelCasedParamKey in params) {
		const paramKey = paramCase(camelCasedParamKey);
		const paramValue = params[camelCasedParamKey as keyof typeof params];

		if (paramValue === undefined) {
			instance.searchParams.delete(paramKey);
		} else if (Array.isArray(paramValue)) {
			instance.searchParams.set(paramKey, paramValue.join(","));
		} else {
			instance.searchParams.set(paramKey, `${paramValue}`);
		}
	}

	// Ensure the `s` parameter is the last parameter, if it exists.
	// @see https://github.com/imgix/imgix-blueprint#securing-urls
	const s = instance.searchParams.get("s");
	if (s) {
		instance.searchParams.delete("s");
		instance.searchParams.append("s", s);
	}

	return instance.toString();
};

Imgix provides a package named imgix-url-params that contains all valid URL parameters and their types. It comes in JSON format. With this, TypeScript types can be generated automatically with friendly comments. The parameters can be autocompleted with helpful links to Imgix’s documentation built in.

The srcset functions would use this core function to build a string. Their implementation should be straightforward and is not included in this RFC.

Supporting a general purpose Imgix library

The proposed helpers are not specific to Prismic. They are valid for any Imgix user. As such, we could treat these helpers as “general purpose” and make them available to anyone as a community open source project.

Such a library could support Imgix features that Prismic users would not use, such as building secure signed URLs and Web Proxy image sources. This could effectively replace Imgix’s official core library, @imgix/js-core, with a simpler, leaner API (at the expense of possibly not having 100% compatibility with Imgix).

Similar unofficial libraries exist, such as Unsplash’s ts-imgix (https://github.com/unsplash/ts-imgix). None take the approach of completely replacing Imgix’s core library with near 100% feature support.

This general purpose library is being developed as part of the exploratory phase of this RFC. For the purposes of this RFC, assume functions like transformImageURL() use this general purpose library in its implementation.

How to provide feedback

Anyone familiar with Prismic’s image handling or wanting an easier image story can provide feedback.

If you have any thoughts, please reply to this issue.

Everything is open for discussion, but the following points are most important:

  • What is your opinion on the proposed function names? Do you have suggestions for better names or comments to consider?
    • transformImageURL(url, params)
    • buildImageSrcSet(url, options)
    • buildImageDPRSrcSet(url, options)
  • Do you think the proposed APIs could be better?
  • Are there any other helpers that could make displaying images from Prismic easier?
  • Should we invest time in a new, simpler open source library for general Imgix users (i.e. non-Prismic users)?

Thanks! 🙂

Create an `asRepositoryName()` helper

Is your feature request related to a problem? Please describe.

When working with Prismic and its API, you may need full repository API endpoint (e.g. https://qwerty.cdn.prismic.io/api/v2) or just the repository name (e.g. qwerty).

@prismicio/client provides a function to create an API endpoint: prismic.getEndpoint("qwerty")

There is no option to go in the reverse direction, however. If you have an API endpoint, you can only get the repository name by using a regex or creating a URL instance. This is verbose and could be error prone.

Describe the solution you'd like

A helper to extract a repository name from a standard Prismic Rest API V2 endpoint could be helpful.

Such a helper could look like the following (the function name is up for debate):

import * as prismicH from "@prismicio/helpers"

const endpoint = "https://qwerty.cdn.prismic.io/api/v2";
const repositoryName = prismicH.asRepositoryName(endpoint)
// => "qwerty"

Note that this does not support any non-standard Prismic Rest API V2 endpoints. If a user has a custom proxy endpoint, for example, this function cannot help.

It does not perform a network request to resolve the repository name. It simply does string manipulation to extract that part it needs.

The above would be equivalent to the following:

const endpoint = "https://qwerty.cdn.prismic.io/api/v2";
const repositoryName = new URL(endpoint).hostname.split('.')[0]

Describe alternatives you've considered

The new URL() method shown above is the alternative. It is noisy and quite imperative.

Additional context

This could be useful specifically for Slice Machine projects. Slice Machine's config file, sm.json, includes an apiEndpoint property (at least it does at the time of this issue). This proposed helper function would allow a user to import sm.json into their project to reuse the API endpoint and the repository name.

Nuxtjs 2 using `prismicH.Element` return error `need an appropriate loader`

Versions

this is my package.json

{
  "name": "simple-nuxt",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "prisma generate && npm run generate",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint:eslint": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
    "eslint": "npm run lint:eslint",
    "audit": "npm audit",
    "lint:stylelint": "stylelint \"**/*.{vue,css}\""
  },
  "dependencies": {
    "@nuxtjs/dotenv": "^1.4.1",
    "@prisma/client": "4.15.0",
    "@prismicio/helpers": "^2.3.9",
    "core-js": "^3.19.3",
    "crypto-js": "^4.1.1",
    "express": "^4.18.2",
    "nuxt": "^2.17.0",
    "vue": "^2.6.14",
    "vue-server-renderer": "^2.6.14",
    "vue-template-compiler": "^2.6.14",
    "webpack": "^4.46.0"
  },
  "devDependencies": {
    "@nuxt/image": "^0.7.1",
    "@nuxtjs/prismic": "^1.4.2",
    "@nuxtjs/tailwindcss": "^6.7.0",
    "postcss": "^8.4.24",
    "prisma": "^4.15.0",
    "vee-validate": "^3.3.0"
  }
}

Steps to reproduce

Using nuxtjs 2 and create a lib folder with a js file :

import * as prismicH from '@prismicio/helpers'
const Elements = prismicH.Element

console.log(Elements)

the error appears with this line of code import * as prismicH from '@prismicio/helpers'

What is actually happening?

image

`isFilled.image` does not work with `ImageField` out of the box

Hello! Seems like a new variation of #41 cropped up in the latest @prismicio packages.

Versions

  • @prismicio/helpers: 2.2.0
  • @prismicio/types: 0.1.27
  • node: v16.14.0
  • typescript: 4.6.2

Steps to reproduce

type Doc = {
  image: ImageField;
};

const d: Doc = { image: {} };

isFilled.image(d.image);

/*
  Argument of type 'Simplify<(EmptyImageFieldImage | FilledImageFieldImage) & Record<never, EmptyImageFieldImage | FilledImageFieldImage>>' is not assignable to parameter of type 'Simplify<(EmptyImageFieldImage | FilledImageFieldImage) & Record<string, EmptyImageFieldImage | FilledImageFieldImage>> | null | undefined'.
*/

What is expected?

isFilled.image shouldn't require a generic argument to be passed in order to typecheck.

What is actually happening?

Code does not typecheck. isFilled.image<null>(d.image); can be used as a workaround.

`isFilled` helper

A helper that determines if a field is filled or not could be helpful.

For example, the following code is needed to check if a Rich Text field is empty (note that a Rich Text field can be stuck with <p></p> even when emptied):

{prismicH.asText(title) && (
        <h3 className="plan__title">
                <PrismicText field={title} />
        </h3>
)}

It doesn't convey intent as well as this:

{prismicH.isFilled(title) && (
        <h3 className="plan__title">
                <PrismicText field={title} />
        </h3>
)}

Link fields are currently difficult to determine if they are filled or not. It is not something that can be inlined with other code (at least I don't think so). Thus, abstracting it to a helper could be useful.

Detecting field types to determine which kind of check to make may be fragile, but it could be possible.

I don't have a proposal on its implementation, but any thoughts on its usefulness?

Provide HTML Serializer children as string

Is your feature request related to a problem? Please describe.

When writing HTML Serializers, the children parameter is an array of strings. Whenever it is used in the return value, it must always be converted into a single string using something like children.join(''). This can be verbose.

Describe the solution you'd like

Since the return value must always be a string, could the HTML Serializer be typed so children is already a flat string?

Before:

const htmlSerializer = {
  heading1: ({ children }) => `<h1>${children.join('')}</h1>,
}

After:

const htmlSerializer = {
  heading1: ({ children }) => `<h1>${children}</h1>,
}

Describe alternatives you've considered

None.

Additional context

This changes the type signature of a Rich Text Serializer so there may be type conflicts. children is expected to always be an array in @prismicio/richtext. We may need to make children a generic that can be overridden by libraries (@lihbr I think you may have done this in the past… sorry if I reverted that!).

Error: Type 'P_2' cannot be used to index type 'FilledImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, FilledImageFieldImage>'

Versions

    "@prismicio/client": "6.6.3",
    "@prismicio/helpers": "2.3.2",
    "@prismicio/next": "0.1.3",
    "@prismicio/react": "2.4.4",
  • node: v16.15.0

Steps to reproduce

git clone --branch prismic-preview-fix https://github.com/jeremytenjo/starter-website.git && cd starter-website && npm i && npm run tests:ts-types

What is expected?

Terminal to have no errors after running npm run tests:ts-types

What is actually happening?

Getting error after running npm run tests:ts-types:

node_modules/@prismicio/helpers/dist/index.d.ts:309:1463 - error TS2536: Type 'P_2' cannot be used to index type 'FilledImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, FilledImageFieldImage>'.

309 }, ThumbnailNames extends Exclude<keyof Field, number | symbol | "url" | "dimensions" | "alt" | "copyright">>(field: Field | ((_prismicio_types.EmptyImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, _prismicio_types.EmptyImageFieldImage | _prismicio_types.FilledImageFieldImage> extends infer T ? { [P in keyof T]: (_prismicio_types.EmptyImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, _prismicio_types.EmptyImageFieldImage | _prismicio_types.FilledImageFieldImage>)[P]; } : never) | (_prismicio_types.FilledImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, _prismicio_types.EmptyImageFieldImage | _prismicio_types.FilledImageFieldImage> extends infer T_1 ? { [P_1 in keyof T_1]: (_prismicio_types.FilledImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, _prismicio_types.EmptyImageFieldImage | _prismicio_types.FilledImageFieldImage>)[P_1]; } : never)) | null | undefined) => field is _prismicio_types.FilledImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, _prismicio_types.FilledImageFieldImage> extends infer T_2 ? { [P_2 in keyof T_2]: (_prismicio_types.FilledImageFieldImage & Record<ThumbnailNames extends string ? Exclude<ThumbnailNames, "url" | "dimensions" | "alt" | "copyright"> : never, _prismicio_types.FilledImageFieldImage>)[P_2]; } : never;

`isFilled.image` is not fully compatible with `ImageField` type

Versions

  • @prismicio/helpers: 2.0.0
  • node: 16.13.2
  • typescript: 4.5.4 (strict option enabled)

Steps to reproduce

When trying to use isFilled.image with a variable of type ImageField (note that there is no generic type variable, especially for the 1st one, ThumbnailNames) tsc complains that the image variable does not have the right type.

const emptyImage: ImageField = {};
isFilled.image(emptyImage);
// Argument of type 'EmptyImageFieldImage' is not assignable to parameter of type '(EmptyImageFieldImage | FilledImageFieldImage) & Record<string, EmptyImageFieldImage | FilledImageFieldImage>

What is expected?

isFilled.image should work with images with no thumbnails, with translates in TS to ImageField aka ImageField<null, FieldState> since there are default types provided for the type variables.

What is actually happening?

Code does not typecheck.

feat: provide `defineHTMLFunctionSerializer` and `defineHTMLMapSerializer` helpers

Is your feature request related to a problem? Please describe.

Function and map serializers are now beautifully typed but often defined outside of asHTML calls for reusability purposes.

This leads to forcing TypeScript users to specifically type their functions/map (which is fine), but also kills any IntelliSense JavaScript users might have had from them.

Describe the solution you'd like

Exposing two functions, defineHTMLFunctionSerializer and defineHTMLMapSerizlizer, that simply receive said arguments and return them, would allow to get seamless IntelliSense for both TypeScript and JavaScript users.

Describe alternatives you've considered

n/a, haven't thought about it much tbh

Additional context

This is pattern somewhat adopted by other technologies, for example siroc: https://github.com/unjs/siroc/blob/main/src/core/package/index.ts#L100

I also adopted that pattern for the 11ty plugin: https://github.com/prismicio-community/eleventy-plugin-prismic/blob/master/src/definePrismicPluginOptions.ts

Helper to resolve all links and serialize all Structured Text fields in a document

A function to traverse a document's fields and convert all Rich Text and Title fields to HTML and text could help users simplify their code.

If they are using asHTML or asText throughout their project, this would allow one call to replace all of them.

This function could be called resolveAndSerializeDocument as it resolves links and serializes Structured Text.

import * as assert from 'assert'
import * as prismic from '@prismicio/client'
import * as prismicH from '@prismicio/helpers'

import { linkResolver, htmlSerializer } from '../utils'

const endpoint = prismic.getEndpoint('qwerty')
const client = prismic.createClient(endpoint)

const document = client.getByUID('blog_post', 'my-post')
const convertedDocument = prismicH.resolveAndSerializeDocument(document, linkResolver, htmlSerializer)

assert.deepEqual(
  convertedDocument.data.title,
  {
    text: 'My Title',          // Serialized via prismicH.asText
    html: '<h1>My Title</h1>', // Serialized via prismicH.asHTML
    data: document.data.title  // The original Rich Text object
  }
)

assert.deepEqual(
  convertedDocument.data.link,
  {
    ...document.data.link
    url: '/resolve-link', // Resolved via prismicH.asLink
  }
)

Detection of Structured Text fields is somewhat unreliable, but not impossible. Every element in the field should contain a type field.

(Credit to @asyarb for the idea)

Include `data` field in `documentToLinkField`

If a document is provided to documentToLinkField for use with asLink, the document's data field should be retained.

Related issue: prismicio/prismic-types#1

documentToLinkField currently copies all standard Link fields except data, which may be populated in normal Fields using fetchLinks or GraphQuery.

return {
link_type: LinkType.Document,
id: prismicDocument.id,
uid: prismicDocument.uid ?? undefined,
type: prismicDocument.type,
tags: prismicDocument.tags,
lang: prismicDocument.lang,
url: prismicDocument.url ?? undefined,
slug: prismicDocument.slugs[0], // Slug field not available with GraphQl
};

asHTML renders hyperlinks with undefined target

Versions

  • @prismicio/helpers: 2.3.3
  • node: v16.13.1

Reproduction

Using asHTML with the default serializer renders hyperlinks with undefined targets.

Steps to reproduce

  • have a RichTextfield with a hyperlink somewhere. e.g.
  • do not set the target
  • in your code use the asHTML helper: asHTML(myRTF)

What is expected?

Hyperlinks should render correctly:

What is actually happening?

The string is undefined: https://github.com/prismicio/prismic-helpers/blob/master/src/lib/serializerHelpers.ts#L75

<a href="mailto:[email protected]" target="undefined" rel="noopener noreferrer">[email protected]</a>

The actual code here is different to the suggested example:
https://prismic.io/docs/technologies/html-serializer#see-all-html-serializer-elements

v2.3.1 broke asHTML serializer api (bug or feature 🤷)

Versions

  • @prismicio/helpers: v2.3.1
  • node: n/a (because demo in codesandbox.io)

Steps to reproduce

  1. Open the following codesandbox link https://codesandbox.io/s/prismicio-helpers-html-serializer-bug-i0eqrs?file=/src/App.tsx
  2. In the codesandbox UI to change project dependencies, switch prismicio/helpers between versions 2.3.1 and 2.3.0
  3. Observe how the outputted HTML is different between v2.3.1 and v2.3.0 by looking at the rendered preview on the right

Reproduction video

prismicio-helpers-html-serializer-change.mp4

Additional Notes

I needed to wrap text coming from Prismic with my own text styling and I didn't want to have nested p, h1 or other tags nested of the same kind (because it's invalid html). For example, I didn't want to have:

<p class="my-paragraph"> <!-- p with my styles -->
  <p>hello world <a href="https://example.com">example</a></p> <!-- p serialized from primisc -->
</p>

I needed to provide my own serializer to asHTML to get rid of the outermost tag coming from prismic to avoid this issue and end up with something like this

<p class="my-paragraph"> <!-- p with my styles -->
  hello world <a href="https://example.com">example</a><!-- content of the p coming from primisc -->
</p>
When things broke

In 2.3.0 the custom serializer content argument had the HTML string of the element currently being processed
In 2.3.1 the custom serializer content argument had the text content of the element currently being processed and no longer the HTML string

I fixed my case by having the serializer return null in all cases except when it had reached the top or outermost tag as suggested here in the docs

  const htmlWithCustomSerializer =
    asHTML(richTextFieldLink, null, (type, _, content, children) => {
      // Stop once parent element is reached to avoid nested h1, p tags, etc.
      // Given our StyledText would provides the outermost tag
      if (type === richTextFieldLink?.[0]?.type) return children;
      else return null;
    }) || "";

The questions

  • Was the serializer content arg on v2.3.0 (and below) having the HTML string of the current element being processed a bug or a feature?
  • Is the change in api from v2.3.1 forward a regression?

HTML Serializer object syntax

I think that most of the use cases for HTML Serializers are for labels (that's a guess). The label property is nested under element.data.label, so if a user has multiple labels, they will still need to use a switch inside their object syntax. In that case, is the object syntax simply overcomplicating things? (Genuine question.)

const htmlSerializer = {
  label: ({ children, element }) => {
    switch (element.data?.label) {
    }
     case 'codespan':
      return `<code>${children.join('')}<code/>`
    case 'highlight':
     return `<mark>${children.join('')}</mark>`
    case 'banner':
      return `<div class="banner">${children.join('')}</div>`
    }
  }
}

As opposed to:

const htmlSerializer = (type, element, content, children) => {
  switch (element.data?.label) {
    case 'codespan':
      return `<code>${children.join('')}<code/>`
    case 'highlight':
      return `<mark>${children.join('')}</mark>`
    case 'banner':
      return `<div class="banner">${children.join('')}</div>`
  }
}

Pardon my janky, untested code snippets.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.