Skip to content

Releases: measuredco/puck

v0.16.2

07 Nov 19:12
Compare
Choose a tag to compare

Bug Fixes

  • always treat data as immutable, fixing Redux issues (51154e9)
  • don't crash if component definition missing (525b506)
  • don't crash when selecting component with no config (cb90f5d), closes #671
  • export missing resolveAllData lib in RSC bundle (2f5fb7b)
  • fix RTL styles in action bar overlay (bf5c5a3)
  • remove internal AutoField and FieldLabel components from bundle (5df1597)
  • remove unused label from AutoField type (18b6f1a)

New Contributors

Full Changelog: v0.16.1...v0.16.2

v0.16.1

07 Oct 21:37
Compare
Choose a tag to compare

Bug Fixes

  • don't delete array field on click in FieldLabel (ed282b9)
  • don't overwrite user input when field recently changed (6126040)
  • don't show field loader if no resolver defined (8c706cd)
  • hide ActionBar.Group border when empty (4345165)
  • prevent item click before iframe load (61e1653)
  • prevent flash of field loader when no data changed (20d7309)
  • respect readOnly styles in AutoField (9ffe817)

Full Changelog: v0.16.0...v0.16.1

v0.16.0

17 Sep 09:57
Compare
Choose a tag to compare

We're celebrating 5,000 stars on GitHub! Thank you to our wonderful community! 🀩

Puck v0.16 is a big release, introducing the headline permissions API and β€” you guessed it β€” quality of life improvements. This one took a while to put together, and we appreciate your patience and support πŸ™

TLDR

  • Permissions: Toggle Puck features like duplication, dragging, deletion through the new permissions and resolvePermissions APIs.
  • Action bar override: Create custom action bars using the actionBar override, or extend the default one using the new <ActionBar> component.
  • iframe style injection: Access the iframe document to inject styles directly, or make other changes, via the new iframe override. We also introduced the emotion-cache plugin for the common Emotion use-case.
  • History injection: Inject the undo/redo history via the a series of new APIs
  • React to actions: React to actions dispatched by Puck via the onAction callback.
  • Optional fields: Optional props are no longer required to define in fields, since they may be defined

Highlights

πŸ” Permissions

Permissions enable you to toggle core Puck functionality globally, on a per-component basis or dynamically. Huge thanks to @xaviemirmon for his efforts on this.

export function Editor() {
  return (
    <Puck
      permissions={{
        delete: false,
        duplicate: true
      }}
    />
  );
}

πŸͺ› Action bar override

The new actionBar override enables you to create a custom action bar overlay, or extend the default one using the <ActionBar> component:

const overrides = {
  actionBar: ({ children }) => (
    <ActionBar label="Actions">
      {/* Render default actions */}
      <ActionBar.Group>{children}</ActionBar.Group>

      {/* Render new actions */}
      <ActionBar.Group>
        <ActionBar.Action onClick={() => console.log("Clicked!")}>
          β˜…
        </ActionBar.Action>
      </ActionBar.Group>
    </ActionBar>
  ),
};

πŸ’… iframe style injection

The iframe override enables you to access the iframe document, making it possible to inject styles into the head:

const overrides = {
  iframe: ({ children, document }) => {
    useEffect(() => {
      if (document) {
        document.body.setAttribute("style", "background: hotpink;");
      }
    }, [document]);

    return <>{children}</>;
  },
};

The new emotion-cache plugin uses this API to create an emotion cache inside the iframe, making Puck easy to use with any Emotion-based component library.

πŸ“œ History injection

Use the new history injection APIs to provide your own undo/redo history via the initialHistory prop, or dynamically via the setHistories and setHistoryIndex functions from usePuck().history.

const historyState = {
  data: {
    root: {
      props: { title: "My History" },
    },
  },
};

export function Editor() {
  return (
    <Puck
      initialHistory={{
        histories: [{ state: historyState }],
        index: 0,
      }}
      // ...
    />
  );
}

React to actions

The onAction API enables you to react to Puck’s internal actions as they’re dispatched:

export function Editor() {
  return (
    <Puck
      onAction={(action, appState, prevAppState) => {
        if (action.type === "insert") {
          console.log("New component was inserted", appState);
        }
      }}
    />
  );
}

Breaking changes

history.data is now history.state

When using the usePuck history API, data is now renamed state.

history.id is now optional (TypeScript)

When using the usePuck history API id is now optional. Puck will always generate an id, but TypeScript may complain.

lastData is now returned as null instead of {} when empty in resolvers

When using the lastData option provided to resolveData or resolveFields functions, and there is no previous data, lastData will now be null instead of {}.

Full changelog

Features

  • add actionBar override for adding component controls (48ec0d7)
  • add automatic RSC export, replacing /rsc bundle (d21eba6)
  • add isDisabled prop to Drawer.Item (cad95b8)
  • add generic type to usePuck hook (01703a9)
  • add iframe override for style injection (7cac376)
  • add initialHistory prop to Puck (54b5a87)
  • add onAction API to track and react to state changes (c7007ac)
  • add permissions API (a43914d)
  • add plugin for injecting Emotion cache (f8a88b9)
  • add resolvePermissions API (f0655f0)
  • add waitForStyles option to iframe config (bc81d9c)
  • call resolveData when new item inserted (3298831)
  • don't mandate fields for optional props (5a219ef)
  • export ActionBar component for use in overrides (04fd6c5)
  • infer Data type from user config (50045bb)
  • make ID optional in History type (BREAKING CHANGE) (d917229)
  • provide ES Module build (ff9076b)
  • rename history.data to history.state (BREAKING CHANGE) (b09244c)
  • show spinner if iframe load takes over 500ms (cfecf54)
  • streamline usePuck history API (c8b2807)
  • upgrade "next" recipe to [email protected] (60fe631)

Bug Fixes

  • add favicon to next recipe to prevent Puck 404 (2c52d27)
  • add missing readOnly state to External fields (bf1449d)
  • always record history on component insert (88c5ab6)
  • don't cache /edit route in Next recipe (94f16b2)
  • don't submit buttons if Puck used in form (f761e5f)
  • ensure demo types are satisfied with TypeScript@5 (958dc25)
  • export missing Plugin type (eb42734)
  • fix crash if component in data is missing from config (0daf478)
  • improve resiliency of iframe CSS for some frameworks, like Mantine (538cb05)
  • make Config and Data types more robust (6bcf555)
  • prevent infinite loop when using plugins with some frameworks (3870871)
  • prevent Tailwind from clashing with viewport...
Read more

v0.15.0

31 May 12:51
Compare
Choose a tag to compare

Puck v0.15.0 introduces the powerful resolveFields API for dynamically defining fields, and exports Puck's internal field component for use within custom fields.

TLDR

  1. Dynamic fields: Use the resolveFields API to dynamically define your fields - great for showing fields conditionally or loading external APIs.
  2. AutoField component: Build custom fields using Puck's own field component for a seamless UI.
  3. Override Publish button: Swap out the publish button without swapping out the entire header.
  4. New puck.isEditing prop: Modify component behaviour based on whether it's inside <Puck> or <Render>.

Highlights

πŸͺ„ Dynamic fields

Dynamic field resolution via the resolveFields API allows you to change the field configuration whenever the props change. You can use this to show and hide fields or even load data from an API.

dynamic.fields.full.page.mp4

Code example:

const config = {
  components: {
    MyComponent: {
      // ...
      resolveFields: (data) => ({
        myField: {
          type: "radio",
          options: [],  // Populate dynamically
        },
      }),
    },
  },
};

πŸ”€ AutoField component

The AutoField component lets you render a Puck field based on a Field object. Use this when building custom fields that need to use Puck-style fields internally.

const CustomField = ({ onChange, value }) => (
  <AutoField field={{ type: "text" }} onChange={onChange} value={value} />
);

🌐 Enable override of Publish button via headerActions

It's now possible to implement a custom Publish button without overriding the entire header by using the headerActions override.

<Puck
  overrides={{
    headerActions: ({ children }) => (
      <>
        {/* children will render default Publish button */}
        {children}
        {/* Or you can define your own */}
        <button>Click me</button>
      </>
    ),
  }}
/>;

This creates a breaking change for existing headerActions overrides, which will now need to render children to show the default Publish button.

πŸ–ŠοΈ New puck.isEditing prop provided to all components

Components now receive the puck.isEditing prop. Use this to toggle functionality based on whether the component is being rendered in the <Puck> or <Render> contexts.

const config = {
  components: {
    MyComponent: {
      render: ({ puck }) => (
        <div style={{ background: puck.isEditing ? "hotpink" : "transparent" }}>
          Hello, world
        </div>
      ),
    },
  },
};

Breaking changes

headerActions override must now render {children} to show default Publish button

In order to support custom Publish buttons, the headerActions override will no longer render the default Publish button unless children are rendered.

<Puck
  overrides={{
    headerActions: ({ children }) => (
      <>
        {/* Render default Publish button */}
        {children}
      </>
    ),
  }}
/>;

Deprecations

Undocumented editMode API deprecated

The undocumented editMode prop is now deprecated in favor of puck.isEditing.

Changelog

Features

  • add AutoField component for using Puck fields inside custom fields (106028b)
  • add isEditing flag to puck object prop (13bb1bd)
  • add resolveFields API for dynamic fields (0a18bdb)
  • allow data prop to accept an empty object (aedd401)
  • bump next recipe to Next@14 (47a27ed)
  • enable override of publish button (breaking change) (480467a)
  • expose previous data to resolveData via lastData param (dd7051e)
  • replace history chevrons with undo/redo icons (91dff22)

Bug Fixes

  • align Drawer behaviour and docs with expectation (e2cd445)
  • animate loader in iframe (151a267)
  • don't inline link stylesheets for more predictable behaviour (c0a331d)
  • don't overflow external inputs inside arrays/objects (42ef582)
  • don't throw warning when user is correctly specifying root props (46aa8ff)
  • don't unintentionally use read-only styles in external fields (acaf727)
  • fix defaultProps for root (9a1cc7c)
  • infer correct value types in Custom fields (5c8c0e1)
  • position field loader relative to sidebar, not fields (2e8936e)
  • show external field modal when using custom interfaces (6e97a0e)
  • show field loader when using field overrides (8ccfa4c)
  • still load iframe if styles fail to load (3e56bc1)

New Contributors

Full Changelog: v0.14.2...v0.15.0

v0.14.2

17 Apr 18:17
Compare
Choose a tag to compare

Puck v0.14.2 addresses numerous stability issues and significantly improves loading performance for iframes.

Changelog

Bug Fixes

  • add DropZone iframe compatablity mode for bug in Safari 17.2, 17.3 and 17.4 (47496c2)
  • check for optionality to handle race condition when dragging (4dbd487)
  • defer iframe event binding until contentWindow is ready (268ea53)
  • don't crash if component is missing after referenced in category (dc93789)
  • don't force height of DropZones in custom interfaces (046c255)
  • don't query iframe document if not ready (2b2ef32)
  • don't throw undefined error if rapidly zooming browser in some environments (282a8b0)
  • fix drag-and-drop when entire Puck component used inside an iframe (23db292)
  • fix support for boolean values in select fields (c4a66ad)
  • make draggable outlines consistent (9008b70)
  • prevent grid layout issues in generated apps (5c05f94)
  • reflect value changes made via resolveData in radio fields (9a7066f)
  • remove peer dependencies causing warnings (041ca64)
  • resolve security warning when additional iframes present (03ab0bd)
  • use 100% width for Puck preview when iframe disabled (#414) (64303c8)
  • use more custom interface friendly styles for iframes (e6e01c6)

Performance Improvements

  • add API for disabling auto-scroll due to performance issues (3e5599e)
  • batch load initial iframe styles (e585f20)
  • don't lock main thread when iframe styles changed (e529e85)
  • reuse host window styles in iframes (e7fe7e0)

New Contributors

Full Changelog: v0.14.1...v0.14.2

v0.14.1

01 Apr 16:39
Compare
Choose a tag to compare

Bug Fixes

  • don't throw undefined error if rapidly zooming browser in some environments (282a8b0)
  • prevent grid layout issues in generated apps (5c05f94)
  • remove peer dependencies causing warnings (041ca64)

Full Changelog: v0.14.0...v0.14.1

v0.14.0

28 Mar 19:44
Compare
Choose a tag to compare

Puck v0.14.0 introduces the long awaited viewport switching feature, with drag-and-drop-friendly iframe rendering for full CSS media query support.

TLDR

  1. Viewport switching: Render your entire Puck preview inside an iframe for full CSS media query support. Override the viewports using the viewports API.
  2. New field APIs: Array and number fields now accept min/max params, and external fields can now render search filters using the familiar fields API.
  3. New component label API: Provide a custom label to use as your component name.
  4. Contentful field package: Easily load your Contentful content into Puck with this pre-configured field.
  5. Color, accessibility and keyboard improvements: A new 12-tint color palette for improved contrast, amongst various other accessibility fixes.

Highlights

πŸ“± Viewport switching

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.

Puck.Viewport.Switching.mp4

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.
        },
      ]}
      // ...
    />
  );
}

πŸ”’ New field APIs

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
    },
  },
},

πŸ”‘ New component label API

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>,
    },
  },
};

Contentful field package

Use the new field-contentful package to load content out of your Contentful space.

NB An issue occurred publishing @measured/[email protected]. We will be introducing @measured/[email protected] soon to address this.

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>;
      },
    },
  },
};

Breaking changes

iframes are enabled by default

Viewport rendering with iframes is enabled by default. If you need to disable this, you can pass iframes={{ enabled: false }} to the Puck component.

Changelog

Features

  • add "name" prop to componentItem override (45bbceb)
  • add min and max APIs to array fields (53b7937)
  • add API to opt-out of iframes (03dd90b)
  • add Contentful field package (d944288)
  • add filter fields to ExternalFields (7a55053)
  • add iframe support (1d0bf57)
  • add min and max APIs to number fields (4932a6e)
  • add selectedItem convenience param to usePuck (c1224d0)
  • add viewport switching (ccf9149)
  • enable mapping of table rows in external fields (d50c56e)
  • expose history via usePuck hook (1b907cb)
  • hide array Add button when array is readOnly (4e27c3f)
  • improve touch, contrast & keyboard a11y (f975d87)
  • refine UI for external field modal (6a2afa1)
  • support custom component labels via the new label param (712fb8e)
  • update to 12-tint color palette (d43da58)
  • use InterVariable font (88532fb)

Bug Fixes

  • avoid FOUC of side bars on mobile (83be956)
  • correctly infer objectFields type from props (e8991cc)
  • don't attempt to resolve data if component missing from config (cc7d391)
  • don't flash nested DropZones on first drag (38c3dc4)
  • don't unexpectedly show DropZone background (2001fa2)
  • ensure font loads for ExternalFields (e9bca75)
  • ensure heading-analyzer updates when content changes (d75df7a)
  • ensure select and radio fields support read only arrays (cbdf66d)
  • fix array field when used on root (95280e6)
  • fix renderDropZone method in editor (2c738dd)
  • lower opacity of DropZone background to support dark backgrounds (9a5c0b8)
  • make getItemSummary optional on ExternalFields, as expected (26bc4ff)
  • only import Puck CSS on editor pages (22a4182)
  • prevent unexpected field behaviour when pressing "Enter" key (bf4f527)
  • use strict return type for resolveData (777cd3c)
  • vertically align field icons (fa92436)

New Contributors

Full Changelog: v0.13.1...v0.14.0

v0.13.1

23 Dec 12:29
Compare
Choose a tag to compare

Bug Fixes

  • don't render plugins twice when using React strict mode (f70c722)
  • replace crypto with uuid lib (a84e06f)

Full Changelog: v0.13.0...v0.13.1

v0.13.0

20 Dec 09:43
Compare
Choose a tag to compare

Puck v0.13.0 introduces some of our most powerful APIs yet, enabling completely custom interfaces, adding support for object fields and mechanisms to restrict DropZones.

TLDR

  1. Custom interfaces: Take complete control of the Puck UI with the new custom interface APIs.
  2. Object fields: Represent objects as fields with the new object field type.
  3. DropZone restrictions: The new allow and disallow props allow you to restrict which components can be dropped into DropZones.
  4. New plugin API (Breaking Change): The plugin API has been updated to align with the new custom interfaces API. This is a breaking change. The plugin API remains experimental.
  5. New transformProps API: The new transformProps API makes it easier to rename props on your components without breaking your payload.
  6. New ui prop: Set the initial UI state for the Puck editor on render.
  7. Add search to external fields: Show a search input in the external field modal, enabling the user to query your external API.

Highlights

🎨 Custom interfaces

It's now possible to create completely custom Puck interfaces to integrate more deeply with your own UI and create a seamless experience for your users.

image

This can be achieved by passing children to the <Puck> component.

import { Puck } from "@measured/puck";

export function Editor() {
  return (
    <Puck>
      <div style={{ background: "hotpink" }}>
        <Puck.Preview />
      </div>
    </Puck>
  );
}

See demo.

πŸͺ The usePuck hook

Access Puck's internals using the usePuck hook to extend Puck's functionality with powerful custom components.

import { Puck, usePuck } from "@measured/puck";

const JSONRenderer = () => {
  const { appState } = usePuck();

  return <div>{JSON.stringify(appState.data)}</div>;
};

export function Editor() {
  return (
    <Puck>
      <JSONRenderer />
    </Puck>
  );
}

πŸ—ƒοΈ Object fields

Object fields enable you to represent your object types with the fields API. No more flattening your props!

const config = {
  components: {
    Example: {
      fields: {
        params: {
          type: "object",
          objectFields: {
            title: { type: "text" },
          },
        },
      },
      render: ({ params }) => {
        return <p>{params.title}</p>;
      },
    },
  },
};

πŸ™… DropZone restrictions

Restrict which components can be passed into a DropZone component with the allow and disallow props.

const MyComponent = () => (
  <DropZone zone="my-content" allow={["HeadingBlock"]} />
);

Deprecations

renderHeader deprecated

The renderHeader prop has been deprecated in favor of the overrides API.

// Before
export function Editor() {
  return (
    <Puck
      renderHeader={({ appState, dispatch }) => ()}
    />
  );
}

// After
export function Editor() {
  return (
    <Puck
      overrides={{
        header: ({ appState, dispatch }) => ()
      }}
    />
  );
}

renderHeaderActions deprecated

The renderHeaderActions prop has been deprecated in favor of the overrides API.

// Before
export function Editor() {
  return (
    <Puck
      renderHeaderActions={({ appState, dispatch }) => ()}
    />
  );
}

// After
export function Editor() {
  return (
    <Puck
      overrides={{
        headerActions: ({ appState, dispatch }) => ()
      }}
    />
  );
}

Breaking changes

renderComponentList removed

The renderComponentList prop has been removed in favor of the overrides API.

// Before
export function Editor() {
  return (
    <Puck
      renderComponentList={({ appState, dispatch }) => ()}
    />
  );
}

// After
export function Editor() {
  return (
    <Puck
      overrides={{
        componentList: ({ appState, dispatch }) => ()
      }}
    />
  );
}

Plugin API revamped

The plugin API has been significantly revamped to match the overrides API.

// Before
export function Editor() {
  return (
    <Puck
      plugins={[
        { renderFields: ({ appState, dispatch }) => () }
      ]}
    />
  );
}

// After
export function Editor() {
  return (
    <Puck
      plugins={[
        overrides: {
          form: ({ appState, dispatch }) => ()
        }
      ]}
    />
  );
}

Changelog

Features

  • add "ui" prop to Puck to set the initial state (71f8b2f)
  • add APIs to restrict components dropped in DropZones (28f24f9)
  • add data migration API (f987324)
  • add generic Config type to Puck and Render components (1c4b97f)
  • add object field type (243278b)
  • add Puck class to outer div (0698a12)
  • add search to external fields (fe3b439)
  • add transformProps lib to migrate component props (1ec2a78)
  • add usePuck hook (13f3ccb)
  • introduce UI overrides API (8a7c325)
  • make onPublish prop optional (60f317f)
  • remove renderComponentList in favour of overrides API (97f65e3)
  • replace existing plugin API with plugin overrides (46cca26)
  • support compositional Puck (22f053f)
  • track isDragging in app state (841ae12)

Bug Fixes

  • don't crash when loading external data into array field items (d13d00b)
  • enable user to pass in config without casting (ee211e2), closes #185
  • fix broken nested array fields (7a3949f)
  • fix initial UI state on mobile (3aa0057)
  • prevent pollution of global styles into component overlay (3fcf8e3)
  • record history when a user selects an item (3a649c9)
  • remove packages triggering superficial security warning (0f52b61)
  • respect label in radio fields (fe550d7)
  • set aria-label on all loaders (9adca27)
  • stop color pollution in external field modals (2e1b5ef)
  • use correct title path in recipes (60244ba)
  • watch puck.config.tsx in Remix recipe (ecb276c)

New Contributors

Full Changelog: v0.12.0...v0.13.0

v0.12.0

23 Nov 11:41
Compare
Choose a tag to compare

The Puck docs now live at https://puckeditor.com/.

Summary

This release introduces support for React Server Components (thanks @4leite), makes huge improvements to responsive behaviour (πŸ™‡β€β™‚οΈ @monospaced) and introduces a Remix recipe (ty @EarthlingDavey).

⚑️ React Server Components

Puck now supports React server components via the included @measured/puck/rsc bundle. You should import Render from this bundle instead of the main bundle if you need to support RSC:

import { Render } from "@measured/puck/rsc";
 
export function Page() {
  return <Render config={config} data={data} />;
}

Docs: https://puckeditor.com/docs/integrating-puck/server-components

πŸ“± Responsive Improvements

Puck now behaves much better on small viewports! We’ll continue to iterate on this experience.

✨ Remix Recipe

The new Remix recipe enables you to generate a Remix Run v2 application configured with Puck.

πŸ’… New CSS imports

You can now import your CSS directly from the Puck package, instead of reaching into dist. This is backwards compatible.

@import "@measured/puck/puck.css";

Changelog

Features

  • support React server components via @measured/puck/rsc bundle (90ac161)
  • add explicit rsc and css exports (0b6a527)
  • improve responsive behaviour (889b4c7)
  • add visibility toggle for right-hand sidebar (3d6c5d4)
  • allow custom fields to set UI state during onChange (388793c)
  • expose field "id" to custom fields (849161e)
  • improve IconButton accessibility (4c71d39)
  • add new monospaced font stack (c484ea6)
  • tweak Field input focus state (8012afd)

Bug Fixes

  • don't enable style pollution of input background color (bb1a76b)
  • don't reset array item labels when changing order (57563e1)
  • ensure field icon and label are vertically aligned (caa40e0)
  • ensure root render receives props from latest data API (abb6ff1)
  • export missing PuckAction type (f22f32d)
  • fix rootResolver behaviour when using recommended root data API (5c13de5)
  • migrate to @hello-pangea/dnd to fix defaultProps warning (2c97362)
  • prevent inconsistent default input font-size (99f90b3)
  • show a default value when no placeholder set on external fields (e30b5b6)
  • stop zones getting wiped out if data prop updated (0c4514f)
  • stop style pollution into array field items (03b89d5)
  • stretch external field table to width of modal (f6d89f6)
  • use correct root data API in next recipe example database (b598144)
  • use Inter font in button type Buttons (1973847)

Full Changelog: v0.11.0...v0.12.0

New Contributors