| 1 | import type { |
| 2 | EditableElementSnapshot, |
| 3 | EditSelectionPayload |
| 4 | } from '@arcsin1/presentation-editor-runtime' |
| 5 | import type { ElementEditDraft } from './types' |
| 6 | |
| 7 | export const EMPTY_ELEMENT_DRAFT: ElementEditDraft = { |
| 8 | html: '', |
| 9 | text: '', |
| 10 | color: '#34402c', |
| 11 | fontSize: '', |
| 12 | fontWeight: '400', |
| 13 | textAlign: 'left', |
| 14 | layoutX: '', |
| 15 | layoutY: '', |
| 16 | layoutWidth: '', |
| 17 | layoutHeight: '', |
| 18 | layoutZIndex: '', |
| 19 | opacity: '1', |
| 20 | backgroundColor: '#ffffff', |
| 21 | objectFit: 'contain', |
| 22 | alt: '', |
| 23 | poster: '', |
| 24 | controls: false, |
| 25 | muted: false, |
| 26 | loop: false, |
| 27 | autoplay: false, |
| 28 | playsInline: true, |
| 29 | preload: 'metadata', |
| 30 | artTextTemplateId: '', |
| 31 | formulaLatex: '', |
| 32 | formulaHtml: '', |
| 33 | formulaDisplayMode: false, |
| 34 | chartType: 'bar', |
| 35 | chartTitle: '', |
| 36 | chartLabels: '', |
| 37 | chartValues: '', |
| 38 | chartDataJson: '', |
| 39 | chartPrimaryColor: '#5d6b4d', |
| 40 | chartAccentColor: '#8fbc8f', |
| 41 | chartTextColor: '#2f3b28', |
| 42 | chartSmooth: true, |
| 43 | chartHorizontal: false, |
| 44 | chartStacked: false, |
| 45 | chartAreaFill: true, |
| 46 | chartShowPoints: true, |
| 47 | chartShowLegend: false, |
| 48 | chartDoughnutCutout: '58', |
| 49 | chartRadarFill: true, |
| 50 | chartConfigJson: '' |
| 51 | } |
| 52 | |
| 53 | export function rgbToHex(value: string | undefined): string { |
| 54 | const text = String(value || '').trim() |
| 55 | if (/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(text)) return text |
| 56 | const match = text.match(/^rgba?\(\s*(\d{1,3})[\s,]+(\d{1,3})[\s,]+(\d{1,3})/i) |
| 57 | if (!match) return '#34402c' |
| 58 | const toHex = (part: string): string => |
| 59 | Math.max(0, Math.min(255, Number(part) || 0)) |
| 60 | .toString(16) |
| 61 | .padStart(2, '0') |
| 62 | return `#${toHex(match[1])}${toHex(match[2])}${toHex(match[3])}` |
| 63 | } |
| 64 | |
| 65 | export function fontSizeToNumber(value: string | undefined): string { |
| 66 | const parsed = Number(String(value || '').replace(/px$/i, '')) |
| 67 | return Number.isFinite(parsed) && parsed > 0 ? String(Math.round(parsed)) : '' |
| 68 | } |
| 69 | |
| 70 | export function normalizeFontWeight(value: string | undefined): string { |
| 71 | const parsed = Number(value) |
| 72 | if (!Number.isFinite(parsed)) return value === 'bold' ? '700' : '400' |
| 73 | return String(Math.max(300, Math.min(800, Math.round(parsed / 100) * 100))) |
| 74 | } |
| 75 | |
| 76 | export function normalizeTextAlign(value: string | undefined): string { |
| 77 | const text = String(value || '').trim() |
| 78 | if (text === 'center' || text === 'right' || text === 'justify') return text |
| 79 | return 'left' |
| 80 | } |
| 81 | |
| 82 | export function opacityToInput(value: string | undefined): string { |
| 83 | const parsed = Number(value) |
| 84 | return Number.isFinite(parsed) ? String(Math.max(0, Math.min(1, parsed))) : '1' |
| 85 | } |
| 86 | |
| 87 | export function buildSelectedElementFromSnapshot(args: { |
| 88 | selector: string |
| 89 | blockId?: string |
| 90 | snapshot: EditableElementSnapshot |
| 91 | }): EditSelectionPayload { |
| 92 | const { selector, blockId, snapshot } = args |
| 93 | const rawZIndex = snapshot.computed.zIndex || '' |
| 94 | const zIndex = rawZIndex && rawZIndex !== 'auto' ? parseInt(rawZIndex, 10) : undefined |
| 95 | return { |
| 96 | selector, |
| 97 | blockId, |
| 98 | label: snapshot.label, |
| 99 | elementTag: snapshot.elementTag, |
| 100 | elementText: snapshot.elementText, |
| 101 | kind: snapshot.kind, |
| 102 | capabilities: snapshot.capabilities, |
| 103 | snapshot: { |
| 104 | ...snapshot, |
| 105 | selector, |
| 106 | blockId |
| 107 | }, |
| 108 | isText: Boolean(snapshot.text?.editable), |
| 109 | text: snapshot.text?.value || '', |
| 110 | html: snapshot.text?.html || '', |
| 111 | style: { |
| 112 | color: snapshot.computed.color || '', |
| 113 | fontSize: snapshot.computed.fontSize || '', |
| 114 | fontWeight: snapshot.computed.fontWeight || '', |
| 115 | textAlign: normalizeTextAlign(snapshot.computed.textAlign), |
| 116 | lineHeight: snapshot.computed.lineHeight || '', |
| 117 | backgroundColor: snapshot.computed.svgPaintColor || snapshot.computed.backgroundColor || '' |
| 118 | }, |
| 119 | bounds: snapshot.metrics.viewport, |
| 120 | viewportBounds: snapshot.metrics.viewport, |
| 121 | pageBounds: snapshot.metrics.page, |
| 122 | translateX: snapshot.metrics.translateX, |
| 123 | translateY: snapshot.metrics.translateY, |
| 124 | zIndex: Number.isFinite(zIndex) ? zIndex : undefined, |
| 125 | editability: { x: true, y: true, width: true, height: true } |
| 126 | } |
| 127 | } |
| 128 |