## v2.0.0

We just shipped `@shadcn/designer` v2.0.0 with typed layer definitions, first-class nested groups, group layout controls, and new hooks for working with layer values and meta.

See the [upgrade guide](/docs/guides/update) for details on how to update your project to v2.0.0.

Here's everything that's new in v2.0.0:

- [Type-Safe Layer Definitions](#type-safe-layer-definitions)
- [Nested Layers and Groups](#nested-layers-and-groups)
- [Group Layout Controls](#group-layout-controls)
- [Layer Value and Meta Hooks](#layer-value-and-meta-hooks)
- [Shared Border, Corner, and Padding Controls](#shared-border-corner-and-padding-controls)

### Type-Safe Layer Definitions

Layer types can now be defined with `createLayerType`. This keeps the `type` name and the shape of each layer's `value` and `meta`, so that you have fully typed layer definitions across your app including actions and hooks.

The setup has three parts:

- Define each custom layer with `createLayerType`.
- Export the final `layerTypes` array that your designer instance uses.
- Register that array with `InferLayerTypes` through module augmentation.

```tsx
import {
  DEFAULT_LAYER_TYPES,
  createLayerType,
  type InferLayerTypes,
} from "@shadcn/designer"

const chartLayer = createLayerType({
  type: "chart",
  name: "Chart",
  defaultValues: {
    name: "Chart",
    value: {
      type: "bar",
      data: [],
    },
    meta: {
      source: "manual",
    },
  },
  render: (layer) => {
    return <ChartRenderer value={layer.value} />
  },
})

// Include the default layer types and your custom layers.
export const layerTypes = [...DEFAULT_LAYER_TYPES, chartLayer]

// Tell @shadcn/designer about the layer registry for this app.
declare module "@shadcn/designer" {
  interface DesignerLayerTypes extends InferLayerTypes<typeof layerTypes> {}
}
```

Once registered, the designer narrows APIs such as `Layer`, `showForLayerTypes`, `useSetLayersValue`, and `useSetLayersMeta` to your app's layer registry.

- See [Type Safety](/docs/concepts/type-safety) and the [`createLayerType`](/docs/reference/types#createlayertype) reference for the full setup.
- See also the [detailed guide](/docs/concepts/layers) for working with layers.

### Nested Layers and Groups

Layers now support hierarchy through `parentId`, and `group` is a built-in layer type. You can group, ungroup, lock, reorder, and render nested documents.

- Added `parentId` to the `Layer` type.
- Added the built-in `group` layer type.
- Added `GROUP_LAYERS` and `UNGROUP_LAYERS` actions with default shortcuts.
- Added `useLayerTree`, `useRootLayers`, and layer tree utilities such as `buildLayerTree`, `getChildren`, `getDescendants`, and `getAncestors`.
- Updated the layer tree pane with drag-and-drop reordering, nested selection, expandable groups, and group-aware lock behavior.

```tsx
import { useLayerTree, useLayersAction } from "@shadcn/designer"

function GroupSelection({ selectedLayerIds }: { selectedLayerIds: string[] }) {
  const layerTree = useLayerTree()
  const layersAction = useLayersAction()

  return (
    <button onClick={() => layersAction("GROUP_LAYERS", selectedLayerIds)}>
      Group {layerTree.length} root layers
    </button>
  )
}
```

Use ⌘ G or Ctrl G to group selected layers, and ⌘ ⇧ G or Ctrl Shift G to ungroup.

### Group Layout Controls

Group layers can now work as freeform or flex containers. The new layout actions expose display, direction, alignment, justification, gap, padding, and wrapping controls for group-specific inspector panels.

```tsx
import {
  ActionLayoutAlign,
  ActionLayoutDirection,
  ActionLayoutDisplay,
  ActionLayoutGap,
  ActionLayoutJustify,
  ActionLayoutPadding,
  ActionLayoutWrap,
  DesignerPane,
  DesignerPaneContent,
  DesignerPaneTitle,
} from "@shadcn/designer"

function GroupPanel() {
  return (
    <DesignerPane showForLayerTypes={["group"]}>
      <DesignerPaneTitle>Group</DesignerPaneTitle>
      <DesignerPaneContent>
        <ActionLayoutDisplay />
        <ActionLayoutDirection />
        <ActionLayoutAlign />
        <ActionLayoutJustify />
        <ActionLayoutGap />
        <ActionLayoutPadding />
        <ActionLayoutWrap />
      </DesignerPaneContent>
    </DesignerPane>
  )
}
```

### Layer Value and Meta Hooks

`useSetLayersValue` and `useSetLayersMeta` provide typed setters for custom layer state. They accept a layer ID, an array of IDs, a layer object, or an array of layer objects, and support updater functions plus `{ history: false }` for internal changes.

```tsx
import { useSelectedLayers, useSetLayersMeta, useSetLayersValue } from "@shadcn/designer"

function ChartActions() {
  const selectedLayers = useSelectedLayers()
  const setLayersValue = useSetLayersValue()
  const setLayersMeta = useSetLayersMeta()
  const chartLayers = selectedLayers.filter((layer) => layer.type === "chart")

  return (
    <div>
      <button onClick={() => setLayersValue(chartLayers, { type: "line", data: [] })}>
        Line
      </button>
      <button
        onClick={() =>
          setLayersMeta(chartLayers, (prev) => ({
            ...prev,
            source: "toolbar",
          }))
        }
      >
        Mark source
      </button>
    </div>
  )
}
```

See the [`useSetLayersValue`](/docs/reference/hooks#usesetlayersvalue) and [`useSetLayersMeta`](/docs/reference/hooks#usesetlayersmeta) references for target forms and generic usage.

### Shared Border, Corner, and Padding Controls

The border, corner, and padding actions have been rebuilt around shared control behavior. They now handle mixed values across multi-selection, expose grouped and per-side controls, and share the same input model used by other numeric designer actions.

- `ActionCorner` supports grouped radius editing and independent corner values.
- `ActionPadding` supports grouped padding and per-side padding.
- `ActionBorder` supports border width and color controls with shared multi-selection behavior.
- `useSharedValues` is available for custom controls that need the same "all selected values match" behavior.

See the [upgrade guide](/docs/guides/update) for upgrading your project to v2.0.0.

---

## Restructured Docs, llms.txt, and Markdown

We've reorganized the docs and added support for LLMs and markdown.

### Docs

The docs are now split into four sections: **Concepts**, **Guides**, **Examples**, and **Reference**. Old URLs redirect automatically.

### llms.txt

We've added [`/llms.txt`](/llms.txt) and [`/llms-full.txt`](/llms-full.txt) endpoints for LLMs and AI tools. Every docs page is also available as markdown by appending `.md` to the URL. You'll find a "View as Markdown" link in the sidebar on each page.

## v1.1.0

We just tagged `@shadcn/designer` v1.1.0 with a new unit system and unified Designer Tool API for managing canvas tools.

- [Unit System](#unit-system)
- [Designer Tool](#designer-tool)
- [Input Scrubber](#input-scrubber)

### Unit System

We now let you work in pixels, millimeters, inches, centimeters, or points with DPI-aware conversions.

- Introduced hooks for reacting to unit changes: `useUnitSystem`, `useSetUnitSystem`, `useDPI`, and `useSetDPI`.
- Added `ActionUnitSelector` for swapping units directly from the toolbar.
- Added a shared `units` library with helpers like `toPixels`, `fromPixels`, `parseValueWithUnit`, and `formatValue` plus `DEFAULT_DPI` and `DPI_PRESETS` presets.
- Updated editor defaults to store `unitSystem` and `dpi`, convert paper sizes from millimeters, and clamp dimension inputs at `0`.
- Refined dimension displays to show converted values with trimmed decimals and localized unit abbreviations.

```tsx
import { useUnitSystem, useSetUnitSystem } from "@shadcn/designer"

function UnitSwitcher() {
  const unitSystem = useUnitSystem()
  const setUnitSystem = useSetUnitSystem()

  return (
    <div className="flex items-center gap-2">
      <span>Units: {unitSystem}</span>
      <button onClick={() => setUnitSystem("mm")}>Millimeters</button>
    </div>
  )
}
```

### Example

This example demonstrates how to use the unit system to display and work with measurements in different units.

### Designer Tool

We've introduced a new tool selection system that allows you to switch between different interaction modes on the canvas. This release includes two core tools:

- **Move Tool (V)** - The default tool for selecting, moving, resizing, and rotating layers
- **Hand Tool (H)** - Pan around the canvas without selecting or moving layers

#### Hooks

**`useDesignerTool()`** - Get the currently active tool

```tsx
import { useDesignerTool } from "@shadcn/designer"

function ToolIndicator() {
  const tool = useDesignerTool()

  return (
    <div>
      Active: {tool === "move" ? "Move Tool" : "Hand Tool"}
    </div>
  )
}
```

**`useSetDesignerTool()`** - Change the active tool programmatically

```tsx
import { useSetDesignerTool } from "@shadcn/designer"

function ToolSwitcher() {
  const setTool = useSetDesignerTool()

  return (
    <div>
      <button onClick={() => setTool("move")}>Move (V)</button>
      <button onClick={() => setTool("hand")}>Hand (H)</button>
    </div>
  )
}
```

#### ActionToolbarTool

Dropdown toolbar button for switching between tools

```tsx
import { ActionToolbarTool } from "@shadcn/designer"

<DesignerToolbar>
  <DesignerToolbarGroup>
    <ActionToolbarTool />
  </DesignerToolbarGroup>
</DesignerToolbar>
```

See the [Hooks Reference](/docs/reference/hooks#usedesignertool) for complete API documentation.

#### Example 

Use the Cursor and Hand buttons in the toolbar to switch between the move and hand tools.

### Input Scrubber

The [`InputGroup`](/docs/reference/ui#inputgroup) component now supports scrubbing for faster adjustments without losing precision.

- Hold the mouse button and drag to scrub an input value.
- Added a `useScrubber` hook that handles pointer locking, acceleration, and modifier shortcuts for fine or coarse adjustments.
- Exposed the hook through the designer entry point so custom controls can share the same interaction model as built-in actions.
- Bundled a visual scrubber cursor that renders while dragging to make state changes easier to track.

```tsx
import * as React from "react"
import { useScrubber } from "@shadcn/designer"

function DimensionScrubber() {
  const { scrubProps, value } = useScrubber({
    value: 120,
    onChange: (next) => console.log("Width", next),
  })

  return (
    <button className="flex items-center gap-2" {...scrubProps}>
      Width: {value}px
    </button>
  )
}
```

#### Continuous Button Press

We've added hold-to-repeat controls to make numeric inputs feel more responsive.

- Added a continuous press controller that emits repeated `onChange` events while increment or decrement buttons remain pressed.
- Integrated the behavior into `InputNumber`, matching keyboard repeat cadence and respecting min/max constraints.
- Tuned acceleration so long presses ramp quickly without overshooting small adjustments.

## v1.0.0

We're excited to announce the release of `@shadcn/designer` v1.0.0 (stable). If you do not have a license, you can get one [here](/docs/pricing).

![v1.0.0](/opengraph-image.jpg)

Here's a list of the new features and improvements:

- **mode** - new `mode` prop to the `<Designer />` component to switch between different layer modes. See the [docs](/docs/reference/designer#mode) for more information.
- **onMount** - We've added a new `onMount` prop to the `<Designer />` component to run a callback when the designer is mounted. Useful for doing additional setup when the designer is ready.
- **defaultLayers** - the `layers` prop has been renamed to `defaultLayers` for uncontrolled components.
- **layers** and **onLayersChange** - We've added new props for controlled `<Designer />` components.
- We've also introduced a layer signature optimization to reduce the number of re-renders.
- We've improved layer snapping to be more accurate.

See the [roadmap](/docs/roadmap) for what's coming next.

**Thank you to all the early adopters who have been using the designer and providing feedback: Mikkel, Sebastian, Piotr, Santosh, Jenny, Alex, Maria, David K., David E., and Sarah.**