Примеры кастомных виджетов
Ниже — практические шаблоны, которые реально используются в MixSlide.
Пример 1. Минимальный текстовый виджет
function Widget() {
const { width, height, text, color } = useParams({
width: { type: "float" },
height: { type: "float" },
text: { type: "text", default: "Привет MixSlide" },
color: { type: "colorGradient", default: "#222222" },
});
const _color = isGradient(color) ? undefined : color;
const _bg = isGradient(color) ? color : "none";
return (
<div style={{
width: `${width}px`,
height: `${height}px`,
color: "#000000",
backgroundImage: _bg,
backgroundColor: _color,
display: "grid",
placeItems: "center",
fontSize: "24px",
}}>
{text}
</div>
);
}
isGradient помогает корректно поддерживать и цвет, и градиентный формат.
![Простое текстовое поле в предпросмотре] []
Пример 2. Кнопка «Перегенерировать» (regenerate)
function Widget() {
const { width, height, seed, recalcBtn } = useParams({
width: { type: "float" },
height: { type: "float" },
seed: { type: "integer", default: 0 },
recalcBtn: {
type: "button",
title: "Перегенерировать",
default: 0,
onClick: (current) => (Number(current) || 0) + 1,
},
});
const { pointsPath } = useBlockMemo("blob", () => {
const points = generateBlobPoints(8, 70, 35, seed + recalcBtn);
return { pointsPath: createSmoothPath(points, false) };
}, [width, height, seed, recalcBtn]);
return (
<svg width="100%" height="100%" viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none">
<path d={pointsPath} fill="#0a7" stroke="#0f0" />
</svg>
);
}
Идея: recalcBtn — это параметр-счётчик, при клике инкрементится через onClick, а ререндер зависит от него через useBlockMemo.
Пример 3. Editable-текст (редактирование на холсте)
function Widget() {
const { width, height, text, font, color } = useParams({
width: { type: "float" },
height: { type: "float" },
text: { type: "text", default: "Нажми двойной клик", linkedParamName: "font" },
font: { type: "font" },
color: { type: "color", default: "#ffffff" },
});
return (
<div style={{ width: "100%", height: "100%" }}>
<div
editable="text"
v1ParamName="text_text"
style={{
width: "100%",
height: "100%",
color,
fontFamily: font?.refId,
fontSize: "38px",
fontFeatureSettings: font?.features,
fontVariationSettings: font?.variant,
}}
>
{text}
</div>
</div>
);
}
Важно:
editable="text"должен указывать имя параметра, который редактируется (text);- для совместимости со старыми виджетами можно добавить
v1ParamName.
![Editable текст в режиме редактирования] []
Пример 4. Работа с control points
function Widget() {
const { width, height, radius, color } = useParams({
width: { type: "float" },
height: { type: "float" },
radius: { type: "integer", min: 2, max: 100, default: 24 },
color: { type: "colorGradient", default: "#ff6b00" },
});
const points = useControlPoints();
const p1 = points.start ?? points.p0 ?? { x: 0, y: 0 };
const p2 = points.end ?? points.p1 ?? { x: width, y: height };
return (
<svg width="100%" height="100%" viewBox={`0 0 ${width} ${height}`} overflow="visible">
<line x1={p1.x} y1={p1.y} x2={p2.x} y2={p2.y} stroke={color} strokeWidth={radius} />
</svg>
);
}
useControlPoints полезен, когда форма редактируется пользователем на холсте (например, для линий/фигур).points — это словарь с ключами идентификаторов контрольных точек (start, p0, p1, …), ключи лучше задавать в самой фигуре/виджете.
Пример 5. svg-виджет с fill/stroke и градиентом
function Widget() {
const { fill, stroke, strokeWidth, svgPathData, viewBoxWidth, viewBoxHeight } = useParams({
fill: { type: "colorGradient", default: "#ffffff" },
stroke: { type: "colorGradient", default: "#000000" },
strokeWidth: { type: "integer", min: 0, step: 1, default: 2 },
svgPathData: { type: "string", default: "" },
viewBoxWidth: { type: "float", default: 100 },
viewBoxHeight: { type: "float", default: 100 },
});
const fillValue = isGradient(fill) ? undefined : fill;
const strokeValue = isGradient(stroke) ? undefined : stroke;
return (
<svg width="100%" height="100%" viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}>
<path
d={svgPathData}
fill={fillValue}
stroke={strokeValue}
strokeWidth={strokeWidth}
vectorEffect="non-scaling-stroke"
/>
</svg>
);
}
fill / stroke в формате градиента лучше обрабатывать через условие isGradient, если логика виджета предполагает fallback на плоский цвет.