 Chris Villa
Chris VillaPuck v0.14 introduces the long awaited viewport switching feature, with drag-and-drop-friendly iframe rendering for full CSS media query support.
viewports API.min/max params, and external fields can now render search filters using the familiar fields API.Puck now supports viewport switching with full iframe rendering, without compromising the drag-and-drop experience. This was a significant effort that required patching the underlying drag-and-drop library to support iframes and CSS transforms, and introducing a new library for syncing styles between host and iframe.
Viewports are enabled by default, and can be customized by passing an array to the viewports API.
import { Puck } from "@measured/puck";
 
export function Editor() {
  return (
    <Puck
      viewports={[
        {
          width: 1440,
          height: "auto", // Optional height. Can be numeric or "auto". Defaults to "auto".
          label: "My Viewport", // Optional. Shown in tooltip.
          icon: <svg />, // Optional. Use lucide-icons to align with Puck UI.
        },
      ]}
      // ...
    />
  );
}Both number and array fields now accept min and max parameters, allowing you to control the minimum and maximum values (or number of values) for user input. Thanks to @jabba-the-bug and @jperasmus for their contributions.
const numberField = {
  type: "number",
  max: 10,
};The new filterFields API on external fields allows you to render filters that are provided to your fetchList method using the familiar fields API.
const externalField = {
  type: "external",
  fetchList: async ({ filters }) => {
    // Query content and apply filters
  },
  filterFields: {
    rating: {
      type: "number", // Render a number field
    },
  },
};Customize the name of your component with the new label API. Thanks to @bwat-dev for contributing this feature.
const config = {
  components: {
    HeadingBlock: {
      label: "Heading Block",
      render: () => <h1>Hello, World</h1>,
    },
  },
};Use the new field-contentful package to load content out of your Contentful space.
import createFieldContentful from "@measured/puck-field-contentful";
 
const config = {
  components: {
    Example: {
      fields: {
        movie: createFieldContentful("movies", {
          space: "my_space",
          accessToken: "abcdefg123456",
        }),
      },
      render: ({ data }) => {
        return <p>{data?.fields.title || "No data selected"}</p>;
      },
    },
  },
};Viewport rendering with iframes is enabled by default. If you need to disable this, you can pass iframes={{ enabled: false }} to the Puck component.
See the GitHub release for a full changelog.
If you’re interested in learning more about Puck, check out the demo or read the docs. If you like what you see, please give us a star on GitHub to help others find Puck too!