import { ComponentType, Defs, Ellipse, getElementBounds, Group, Rect, } from '../../jsx'; import { ItemDesc, ItemIconCircle, ItemLabel } from '../components'; import { DropShadow } from '../defs'; import { getItemProps } from '../utils'; import { registerItem } from './registry'; import type { BaseItemProps } from './types'; export interface CapsuleItemProps extends BaseItemProps { width?: number; height?: number; gap?: number; iconPadding?: number; } export const CapsuleItem: ComponentType = (props) => { const [ { datum, indexes, width = 300, height = 80, gap = 12, positionH = 'normal', iconPadding = height / 10, themeColors, }, restProps, ] = getItemProps(props, ['width', 'height', 'gap', 'iconPadding']); // Capsule border radius and icon size (icon with some padding inside) const borderRadius = height / 2; const iconSize = height - iconPadding * 2; // Icon diameter with padding // Calculate positions based on positionH and icon presence const isFlipped = positionH === 'flipped'; const hasIcon = !!datum.icon; // Calculate text area dimensions const textWidth = hasIcon ? width - height - gap : width - gap * 2; const textX = hasIcon ? (isFlipped ? gap : height) : gap; const textAlign = hasIcon ? (isFlipped ? 'right' : 'left') : 'center'; const labelProps = { indexes, width: textWidth, alignHorizontal: textAlign, alignVertical: 'middle', fontSize: 16, fontWeight: '600', fill: themeColors.colorWhite, } as const; // Get label bounds to calculate layout const labelBounds = getElementBounds( {datum.label}, ); const descProps = { indexes, width: textWidth, alignHorizontal: textAlign, alignVertical: 'top', fontSize: 12, lineNumber: 1, fill: themeColors.colorWhite, } as const; // Get desc bounds to calculate layout const descBounds = getElementBounds( datum.desc ? {datum.desc} : null, ); // Calculate vertical positions for text elements const textGap = 4; const totalTextHeight = labelBounds.height + textGap + descBounds.height; const textStartY = (height - totalTextHeight) / 2; const labelY = textStartY; const descY = labelY + labelBounds.height + textGap; // Calculate icon position (centered in the circle area with padding) const iconX = isFlipped ? width - height + iconPadding : iconPadding; const iconY = iconPadding; return ( {/* Capsule background */} {/* Icon - white background with primary color icon */} {datum.icon && ( <> )} {/* Label */} {datum.label && ( {datum.label} )} {/* Description */} {datum.desc && ( {datum.desc} )} ); }; registerItem('capsule-item', { component: CapsuleItem, composites: ['icon', 'label', 'desc'], });