import type { ComponentType, JSXElement } from '../../jsx';
import { Defs, Ellipse, getElementBounds, Group, Path } from '../../jsx';
import {
BtnAdd,
BtnRemove,
BtnsGroup,
ItemIcon,
ItemsGroup,
ShapesGroup,
} from '../components';
import { FlexLayout } from '../layouts';
import { getColorPrimary, getPaletteColor, getThemeColors } from '../utils';
import { registerStructure } from './registry';
import type { BaseStructureProps } from './types';
// W 型路径参数
const DX = 240;
const DY = 130;
const ITEM_TO_PATH_GAP = 105;
// W 型路径宽度
const W_PATH_W = 12;
// 光晕尺寸 (Ellipse W/H)
const GLOW_W = 120; // 椭圆宽度 (水平对角线)
const GLOW_H = 50; // 椭圆高度 (垂直对角线)
const GLOW_OPACITY = 0.6; // 控制光晕的透明度,实现颜色调淡
// 原始装饰性 Path 的 D 属性
const DECO_PATH_1 =
'M132.821 50.6599L87.6795 76.8925C78.0629 82.4807 62.4238 82.4807 52.7445 76.8925L7.30824 50.6599C2.43719 47.8482 0.00459679 44.1562 0.0152907 40.472L3.17695e-05 45.6925C-0.0101404 49.378 2.42245 53.0686 7.29298 55.8803L52.7289 82.1129C62.4094 87.7011 78.0485 87.7011 87.6652 82.1129L132.806 55.8803C137.583 53.1038 139.975 49.4705 139.986 45.832L140 40.6116C139.989 44.2501 137.598 47.8834 132.821 50.6599Z';
const DECO_PATH_2 =
'M132.707 30.4224C142.386 36.0119 142.437 45.0704 132.821 50.6599L87.6795 76.8925C78.0629 82.4807 62.4238 82.4807 52.7445 76.8925L7.30825 50.6599C-2.37126 45.0717 -2.42225 36.0132 7.19414 30.4237L52.335 4.19115C61.9517 -1.39705 77.5908 -1.39705 87.2713 4.19115L132.707 30.4224Z';
// 装饰元素的偏移量 - 改为正值
const DECO_OFFSET_X = 70 + W_PATH_W / 2;
const DECO_OFFSET_Y = 40 + W_PATH_W / 2;
export interface SequenceZigzagStepsProps extends BaseStructureProps {
dx?: number;
dy?: number;
iconSize?: number;
}
// 滤镜定义
const GlowFilter = (
);
export const SequenceZigzagSteps: ComponentType = (
props,
) => {
const { Title, Item, data, options, dx = DX, dy = DY, iconSize = 30 } = props;
const { title, desc, items = [] } = data;
const titleContent = Title ? : null;
const colorPrimary = getColorPrimary(options);
if (items.length === 0) {
const btnAddElement = ;
return (
{GlowFilter}
{titleContent}
{btnAddElement}
);
}
const itemBounds = getElementBounds(
,
);
const btnBounds = getElementBounds();
const btnElements: JSXElement[] = [];
const itemElements: JSXElement[] = [];
const pathElements: JSXElement[] = [];
const decoElements: JSXElement[] = [];
const iconElements: JSXElement[] = [];
let currentX = 0;
let currentY = 0;
let pathD = '';
let minPathY = Infinity;
let maxItemY = -Infinity;
let minDecoX = Infinity;
let minDecoY = Infinity;
const pathPoints: Array<{ x: number; y: number }> = [];
// Pass 1: 计算路径点和装饰元素的边界
items.forEach((item, index) => {
const cx = currentX;
const cy = currentY;
pathPoints.push({ x: cx, y: cy });
minPathY = Math.min(minPathY, cy);
// 计算装饰元素的位置
const decoX = cx - DECO_OFFSET_X;
const decoY = cy - DECO_OFFSET_Y;
minDecoX = Math.min(minDecoX, decoX);
minDecoY = Math.min(minDecoY, decoY);
const isPeak = index % 2 === 0;
if (index < items.length - 1) {
currentX += dx;
currentY = isPeak ? currentY + dy : currentY - dy;
}
});
// 计算偏移量以确保所有元素都在正坐标
const offsetX = Math.max(0, -minDecoX);
const offsetY = Math.max(0, -minDecoY);
currentX = 0;
currentY = 0;
// Pass 2: 放置元素,应用偏移量
items.forEach((item, index) => {
const indexes = [index];
const pathPoint = pathPoints[index];
const cx = pathPoint.x + offsetX;
const cy = pathPoint.y + offsetY;
const currentColor = getPaletteColor(options, indexes);
// 装饰元素 - 确保坐标为正值
const decoX = Math.max(0, cx - DECO_OFFSET_X);
const decoY = Math.max(0, cy - DECO_OFFSET_Y);
const glowX = 10;
const glowY = GLOW_H + 10;
const { colorPrimaryBg } = getThemeColors({
colorPrimary: currentColor,
});
decoElements.push(
,
);
// Icon 元素
if (item.icon) {
const iconX = Math.max(0, cx - iconSize / 2 - W_PATH_W / 2);
const iconY = Math.max(0, cy - iconSize / 2 - W_PATH_W / 2);
iconElements.push(
,
);
}
// Item 元素和按钮
const itemX = cx - itemBounds.width / 2 - W_PATH_W / 2;
const itemY = Math.max(0, cy + ITEM_TO_PATH_GAP - W_PATH_W / 2);
maxItemY = Math.max(maxItemY, itemY + itemBounds.height);
if (index === 0) {
pathD = `M ${cx} ${cy}`;
} else {
pathD += ` L ${cx} ${cy}`;
}
itemElements.push(
,
);
btnElements.push(
,
);
if (index < items.length - 1) {
const nextPoint = pathPoints[index + 1];
const nextCx = nextPoint.x + offsetX;
const nextCy = nextPoint.y + offsetY;
const btnAddX = Math.max(0, cx + (nextCx - cx) / 2 - btnBounds.width / 2);
const btnAddY = Math.max(
0,
cy + (nextCy - cy) / 2 - btnBounds.height / 2,
);
btnElements.push(
,
);
} else {
btnElements.push(
,
);
}
});
if (pathD) {
const finalX = (pathPoints[pathPoints.length - 1]?.x || 0) + offsetX;
pathElements.push(
,
);
}
return (
{GlowFilter}
{titleContent}
{[...pathElements, ...decoElements, ...iconElements]}
{itemElements}
{btnElements}
);
};
registerStructure('sequence-zigzag-steps', {
component: SequenceZigzagSteps,
composites: ['title', 'item'],
});