Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): enhance customisation with slots and render function #167

Merged
merged 6 commits into from
Dec 3, 2024

Conversation

theisel
Copy link
Owner

@theisel theisel commented Dec 3, 2024

This feature introduces new customisation options for fine-tuning the rendering of Portable Text content.

⚠️ This feature requires Astro v4.6.0+ for compatibility due to issues with slots in earlier versions.

Changes Made:

  • Enabled the use of slots in the PortableText component. Users can now use Astro's slot syntax to modify the rendering of specific elements, providing more control over the overall structure and layout. The slot name options are type, block, list, listItem, mark, text and hardBreak.

    In the example below, CustomBlock is passed in to components.block option and when using slots it will be passed in as the Component prop to further enhance the output. If no custom block component is defined, Component will be astro-portabletext block component.

/* .astro */
---
import { PortableText } from "astro-portabletext";
import CustomBlock from "./CustomBlock.astro";

const portableText = [
  {
    _type: 'block',
    _key: 'a1ph4',
    style: 'normal',
    markDefs: [],
    children: [
      {
        _type: 'span',
        _key: 'c961f',
        text: 'This is a Portable Text example.',
        marks: [],
      },
    ],
  },
];
---

<PortableText value={ portableText } components={{ block: CustomBlock }}>

  <fragment slot="block">{({ Component /* CustomBlock */, props, children }) => (
    <Component {...props} class="block">{children}</Component>
  )}</fragment>

</PortableText>

<style>
  .block:where(h1, h2) {
    /* some styles */
  }
</style>
  • Added a render function to usePortableText. This function allows users to customise the output of child nodes, such as modifying text content, changing how links are rendered, or conditionally rendering elements.
/* CustomBlock.astro */
---
import type { Block, Props as $ } from "astro-portabletext/types";
import { usePortableText } from "astro-portabletext/utils";

export type Props = $<Block>;

const { node, isInline, index, ...attrs} = Astro.props;
const { render, getDefaultComponent } = usePortableText(node);

const DefaultBlock = getDefaultComponent(); // In this `block` context, it returns `astro-portabletext` block component

const styleIs = (style: string) => style === node.style;
---

{
  styleIs("h1") ? (
    <h1 {...attrs}>{render({
      text: ({ props }) => props.node.text.replace("fox", "🦊") // Use the render function to customise the output
    })}</h1>
  ) : (
    <DefaultBlock {...Astro.props}>
      <slot />
    </DefaultBlock>
  )
}

Closes #158

- Enable customisation with slots in the `PortableText` component
- Add a `render` function to `usePortableText` for granular, node-level customization

Closes #158
Cache nodes and components in a WeakMap to improve lookup performance
…ibility issues

Require Astro 4.6.0+ for compatibility due to issues with slots in earlier versions.
@theisel theisel merged commit 9d6a9e8 into main Dec 3, 2024
2 checks passed
@theisel theisel deleted the feat--render-function branch December 3, 2024 03:40
@github-actions github-actions bot mentioned this pull request Dec 3, 2024
This was referenced Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Where to perform content transformations?
1 participant