Size Panel (Canvas Size)
The default SizePanel provides common size presets (Instagram / poster / business card / A4) and a custom width/height input.
Two common customizations:
- Change the preset list (your company's standard spec sheet)
- Replace the UI completely (group by business, show thumbnails)
Scenario 1: custom size list
Override the default size Section with your own:
import { observer } from 'mobx-react-lite';
import { Button } from 'antd';
import { ImageUpscale } from 'lucide-react';
import {
SectionTab,
DEFAULT_SECTIONS,
SidePanel,
} from '@ydesign/react-editor/side-panel';
import type { Section } from '@ydesign/react-editor/side-panel';
// Your preset sizes (in pixels)
const AVAILABLE_SIZES = [
{ label: 'Square · 1000 × 1000', width: 1000, height: 1000 },
{ label: 'Vertical · 750 × 1334', width: 750, height: 1334 },
{ label: 'Landscape · 1920 × 1080', width: 1920, height: 1080 },
{ label: 'Print · A4 (300dpi)', width: 2480, height: 3508 },
{ label: 'Business card · 90×54mm', width: 1063, height: 638 },
];
const CustomSizeSection: Section = {
name: 'size', // 👈 override the built-in
Tab: observer(props => (
<SectionTab name="Canvas size" {...props}>
<ImageUpscale size={20} />
</SectionTab>
)),
Panel: observer(({ store }) => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, padding: 4 }}>
{AVAILABLE_SIZES.map(({ label, width, height }) => {
const active = store.width === width && store.height === height;
return (
<Button
key={label}
block
type={active ? 'primary' : 'default'}
onClick={() => store.setSize({ width, height })}
>
{label}
</Button>
);
})}
</div>
)),
};
const sections = DEFAULT_SECTIONS.map(s =>
s.name === 'size' ? CustomSizeSection : s
);
<SidePanel store={store} sections={sections} />;
Key points:
store.setSize({ width, height })triggers the resize- Internally it calls
workareaHandler.setSize, fits to screen, and pushes history store.width/store.heightare reactive, soobserverkeeps the "active" button correct
Scenario 2: unit conversion
Print projects often think in mm / inches but Fabric's canvas is pixels. Use store.setUnit({ unit, dpi }):
const AVAILABLE_PRINT_SIZES = [
{ label: 'A4 Portrait', unit: 'mm', dpi: 300, width: 210, height: 297 },
{ label: 'A4 Landscape', unit: 'mm', dpi: 300, width: 297, height: 210 },
{ label: 'Business card', unit: 'mm', dpi: 300, width: 90, height: 54 },
];
// On click
onClick={() => {
store.setUnit({ unit: 'mm', dpi: 300 });
// setSize still takes pixels — convert with: mm * dpi / 25.4
const mmToPx = (mm: number) => Math.round((mm * 300) / 25.4);
store.setSize({
width: mmToPx(210),
height: mmToPx(297),
});
}}
store.unit / store.dpi are reactive — rulers and related UI will pick up the change.
Scenario 3: grouped size hub
For products with multiple categories (social / print / e-commerce / …), a more structured UI:
const SIZE_GROUPS = [
{
group: 'Social media',
items: [
{ label: 'Instagram square', width: 1080, height: 1080 },
{ label: 'Instagram story', width: 1080, height: 1920 },
{ label: 'WeChat Moments', width: 1242, height: 828 },
],
},
{
group: 'Print',
items: [
{ label: 'Poster · A2', width: 4961, height: 7016 },
{ label: 'A4', width: 2480, height: 3508 },
],
},
];
const GroupedSizeSection: Section = {
name: 'size',
Tab: /* ... */,
Panel: observer(({ store }) => (
<div>
{SIZE_GROUPS.map(({ group, items }) => (
<div key={group} style={{ marginBottom: 16 }}>
<h4>{group}</h4>
{items.map(it => (
<Button key={it.label} block onClick={() => store.setSize(it)}>
{it.label} · {it.width}×{it.height}
</Button>
))}
</div>
))}
</div>
)),
};
Related APIs
| API | Purpose |
|---|---|
store.setSize({ width, height }) | Resize the canvas (pushes history) |
store.setUnit({ unit, dpi }) | Change canvas unit |
store.width / store.height | Current pixel dimensions (reactive) |
store.unit / store.dpi | Current unit + DPI (reactive) |
store.editor?.workareaHandler.setSize(...) | Low-level; store.setSize is enough for most cases |