Skip to content

Latest commit

 

History

History

pt-to-html

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

@portabletext-typed/to-html

NPM Downloads GitHub commit activity (branch) GitHub Repo stars GitHub contributors GitHub issues by-label Minified Size License

GitHub Sponsors

@portabletext/to-html with typed arguments

Page Contents

Install

npm install @portabletext/to-html @portabletext-typed/to-html

Usage

After using @sanity-typed/types and @sanity-typed/client and you have typed blocks, use toHTML from this library as you would from @portabletext/to-html to get fully typed arguments!

post.ts:

// import { defineArrayMember, defineField, defineType } from "sanity";
import {
  defineArrayMember,
  defineField,
  defineType,
} from "@sanity-typed/types";

/** No changes using defineType, defineField, and defineArrayMember */
export const post = defineType({
  name: "post",
  type: "document",
  title: "Post",
  fields: [
    defineField({
      name: "content",
      type: "array",
      title: "Content",
      validation: (Rule) => Rule.required(),
      of: [
        defineArrayMember({ type: "image" }),
        defineArrayMember({
          type: "block",
          of: [defineArrayMember({ type: "file" })],
          styles: [
            { title: "Normal", value: "normal" as const },
            { title: "Foo", value: "foo" as const },
          ],
          lists: [
            { title: "Bullet", value: "bullet" as const },
            { title: "Bar", value: "bar" as const },
          ],
          marks: {
            decorators: [
              { title: "Strong", value: "strong" as const },
              { title: "Baz", value: "baz" as const },
            ],
            annotations: [
              defineArrayMember({
                name: "link",
                type: "object",
                title: "Link",
                fields: [
                  defineField({
                    name: "href",
                    type: "string",
                    validation: (Rule) => Rule.required(),
                  }),
                ],
              }),
              defineArrayMember({
                name: "qux",
                type: "object",
                title: "Qux",
                fields: [
                  defineField({
                    name: "value",
                    type: "string",
                    validation: (Rule) => Rule.required(),
                  }),
                ],
              }),
            ],
          },
        }),
      ],
    }),
  ],
});

with-portabletext-to-html.tsx:

import type { InferGetStaticPropsType } from "next";
import { Fragment } from "react";

// import { toHTML } from "@portabletext/to-html";
import { toHTML } from "@portabletext-typed/to-html";

import { client } from "../sanity/client";

export const getStaticProps = async () => ({
  props: {
    posts: await client.fetch('*[_type=="post"]'),
  },
});

const Index = ({ posts }: InferGetStaticPropsType<typeof getStaticProps>) => (
  <>
    <h1>Posts</h1>
    {posts.map(({ _id, content }) => (
      <Fragment key={_id}>
        <h2>Post</h2>
        <div
          dangerouslySetInnerHTML={{
            // Typed Components!
            __html: toHTML(content, {
              components: {
                types: {
                  // From Siblings
                  image: ({ isInline, value }) => `
                    <div>
                      typeof ${isInline} === false,
                      <br />
                      typeof ${JSON.stringify(value)} === ImageValue,
                    </div>`,
                  // From Children
                  file: ({ isInline, value }) => `
                    <span>
                      typeof ${isInline} === true,
                      typeof ${JSON.stringify(value)} === FileValue,
                    </span>`,
                },
                block: {
                  // Non-Default Styles
                  foo: ({ children, value }) => `
                    <div>
                      typeof ${JSON.stringify(
                        value
                      )} === PortableTextBlock\\< ... \\> & { style: "foo" },
                      ${children}
                    </div>`,
                },
                list: {
                  // Non-Default Lists
                  bar: ({ children, value }) => `
                    <ul>
                      <li>typeof ${JSON.stringify(
                        value
                      )} === ToolkitPortableTextList & { listItem: "bar"; },</li>
                      ${children}
                    </ul>`,
                },
                listItem: {
                  // Non-Default Lists
                  bar: ({ children, value }) => `
                    <li>
                      typeof ${JSON.stringify(
                        value
                      )} === PortableTextBlock\\< ... \\> & { listItem: "bar" },
                      ${children}
                    </li>`,
                },
                marks: {
                  // Non-Default Decorators
                  baz: ({ children, markKey, markType, value }) => `
                    <span>
                      typeof ${value} === undefined,
                      typeof ${markKey} === "baz",
                      typeof ${markType} === "baz",
                      ${children}
                    </span>`,
                  // Non-Default Annotations
                  qux: ({ children, markKey, markType, value }) => `
                    <span>
                      typeof ${JSON.stringify(value)} === {
                        _key: string,
                        _type: "qux",
                        value: typeof ${value.value} === string,
                      },
                      typeof ${markKey} === string,
                      typeof ${markType} === "qux",
                      ${children}
                    </span>`,
                },
              },
            }),
          }}
        />
      </Fragment>
    ))}
  </>
);

export default Index;