Giter VIP home page Giter VIP logo

python-portabletext-html's Introduction

pypi test code coverage supported python versions

Portable Text HTML Renderer for Python

This package generates HTML from Portable Text.

For the most part, it mirrors Sanity's own block-content-to-html NPM library.

Installation

pip install portabletext-html

Usage

Instantiate the PortableTextRenderer class with your content and call the render method.

The following content

from portabletext_html import PortableTextRenderer

renderer = PortableTextRenderer({
    "_key": "R5FvMrjo",
    "_type": "block",
    "children": [
        {"_key": "cZUQGmh4", "_type": "span", "marks": ["strong"], "text": "A word of"},
        {"_key": "toaiCqIK", "_type": "span", "marks": ["strong"], "text": " warning;"},
        {"_key": "gaZingsA", "_type": "span", "marks": [], "text": " Sanity is addictive."}
    ],
    "markDefs": [],
    "style": "normal"
})
renderer.render()

Generates this HTML

<p><strong>A word of warning;</strong> Sanity is addictive.</p>

Supported types

The block and span types are supported out of the box.

Custom types

Beyond the built-in types, you have the freedom to provide your own serializers to render any custom _type the way you would like to.

To illustrate, if you passed this data to the renderer class:

from portabletext_html import PortableTextRenderer

renderer = PortableTextRenderer({
    "_type": "block",
    "_key": "foo",
    "style": "normal",
    "children": [
        {
            "_type": "span",
            "text": "Press, "
        },
        {
            "_type": "button",
            "text": "here"
        },
        {
            "_type": "span",
            "text": ", now!"
        }
    ]
})
renderer.render()

The renderer would actually throw an error here, since button does not have a corresponding built-in type serializer by default.

To render this text you must provide your own serializer, like this:

from portabletext_html import PortableTextRenderer


def button_serializer(node: dict, context: Optional[Block], list_item: bool):
    return f'<button>{node["text"]}</button>'


renderer = PortableTextRenderer(
    ...,
    custom_serializers={'button': button_serializer}
)
output = renderer.render()

With the custom serializer provided, the renderer would now successfully output the following HTML:

<p>Press <button>here</button>, now!</p>

Supported mark definitions

The package provides several built-in marker definitions and styles:

decorator marker definitions

  • em
  • strong
  • code
  • underline
  • strike-through

annotation marker definitions

  • link
  • comment

Custom mark definitions

Like with custom type serializers, additional serializers for marker definitions and styles can be passed in like this:

from portabletext_html import PortableTextRenderer

renderer = PortableTextRenderer(
    ...,
    custom_marker_definitions={'em': ComicSansEmphasis}
)
renderer.render()

The primary difference between a type serializer and a mark definition serializer is that the latter uses a class structure, and has three required methods.

Here's an example of a custom style, adding an extra font to the built-in equivalent serializer:

from portabletext_html.marker_definitions import MarkerDefinition


class ComicSansEmphasis(MarkerDefinition):
    tag = 'em'

    @classmethod
    def render_prefix(cls, span: Span, marker: str, context: Block) -> str:
        return f'<{cls.tag} style="font-family: "Comic Sans MS", "Comic Sans", cursive;">'

    @classmethod
    def render_suffix(cls, span: Span, marker: str, context: Block) -> str:
        return f'</{cls.tag}>'

    @classmethod
    def render_text(cls, span: Span, marker: str, context: Block) -> str:
        # custom rendering logic can be placed here
        return str(span.text)

    @classmethod
    def render(cls, span: Span, marker: str, context: Block) -> str:
        result = cls.render_prefix(span, marker, context)
        result += str(span.text)
        result += cls.render_suffix(span, marker, context)
        return result

Since the render_suffix and render methods here are actually identical to the base class, they do not need to be specified, and the whole example can be reduced to:

from portabletext_html.marker_definitions import MarkerDefinition  # base
from portabletext_html import PortableTextRenderer


class ComicSansEmphasis(MarkerDefinition):
    tag = 'em'

    @classmethod
    def render_prefix(cls, span: Span, marker: str, context: Block) -> str:
        return f'<{cls.tag} style="font-family: "Comic Sans MS", "Comic Sans", cursive;">'


renderer = PortableTextRenderer(
    ...,
    custom_marker_definitions={'em': ComicSansEmphasis}
)
renderer.render()

Supported styles

Blocks can optionally define a style tag. These styles are supported:

  • h1
  • h2
  • h3
  • h4
  • h5
  • h6
  • blockquote
  • normal

Missing features

For anyone interested, we would be happy to see a default built-in serializer for the image type added. In the meantime, users should be able to serialize image types by passing a custom serializer.

Contributing

Contributions are always appreciated ๐Ÿ‘

For details, see the CONTRIBUTING.md.

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.