import { get, isUndefined, round } from 'lodash'; import { SilkeCSSContextType } from './silke-css-context'; let start, end; export const FORMAT_PRECISION = { px: 1, em: 2, rem: 2, percent: 1, deg: 1, rad: 3, vh: 1, vw: 1, vmax: 1, vmin: 1, s: 2, }; export const FORMAT_LABELS = { px: 'Pixels', '%': 'Percentage', vh: 'Viewport height', vw: 'Viewport width', vmin: 'Viewport max dimension', vmax: 'Viewport min dimension', em: 'Font-size relative', deg: 'º', rad: 'Radians', s: 'Seconds', }; export function roundCSSNumber( value: number, format: string, min?: number, max?: number, precisionOverride?: number, ): number { if (!isUndefined(min) && value < min) value = min; else if (!isUndefined(max) && value > max) value = max; const precision = precisionOverride ?? get(FORMAT_PRECISION, format, 1); return round(value, precision); } export function formatNumberForDisplay(value: string) { return value?.replace('deg', 'º').replace('rad', 'r'); } export function convertCSSNumberString( numberText: string, format: string, min?: number, max?: number, ): number { if (numberText.length) { try { const value = parseFloat(numberText.replace(/,/g, '.').replace(/(?![0-9+*/\-.])./g, '')) || 0; return roundCSSNumber(value, format, min, max); } catch (e) { console.warn(e); } } return 0; } export function convertCSSNumberFormat( value: number, fromFormat: string, toFormat: string, context: SilkeCSSContextType, min?: number, max?: number, axis?: 'x' | 'y', ): string { if (toFormat === 'none') return `${value}`; if (toFormat === 'auto') return 'auto'; if (fromFormat === 'auto') value = 1; const fromScale = getFormatScale(fromFormat, context, axis); const toScale = getFormatScale(toFormat, context, axis); value = (value * fromScale) / toScale; return roundCSSNumber(value, toFormat, min, max) + toFormat; } function getFormatScale( format: string, context: SilkeCSSContextType, axis: 'x' | 'y' = 'x', ): number { switch (format) { case '': case 'auto': if (!context.self) { console.warn( 'Not able to format correctly form auto, missing self dimension in css context', ); return 1; } return context.self[axis === 'x' ? 0 : 1]; case 'px': return 1; case '%': return context.container ? context.container[axis === 'x' ? 0 : 1] / 100 : 1; case 'vh': return context.viewport[1] / 100; case 'vw': return context.viewport[0] / 100; case 'vmax': return Math.max(context.viewport[0] / 100, context.viewport[1] / 100); case 'vmin': return Math.min(context.viewport[0] / 100, context.viewport[1] / 100); case 'em': return context.fontSize || 14; } return 1; } export function getDragCursorImage(): Promise { return new Promise((resolve) => { const img = new Image(); img.onload = () => resolve(img); img.width = 35; img.height = 20; img.src = `data:image/svg+xml,%3Csvg height='35' viewBox='0 0 35 35' width='35' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='m9 17.9907v.005l5.997 5.996.001-3.999h1.999 2.02v4l5.98-6.001-5.98-5.999.001 4.019-2.021.002h-2l.001-4.022zm1.411.003 3.587-3.588-.001 2.587h3.5 2.521v-2.585l3.565 3.586-3.564 3.585-.001-2.585h-2.521l-3.499-.001-.001 2.586z' fill='%23fff'/%3E%3Cpath d='m17.4971 18.9932h2.521v2.586l3.565-3.586-3.565-3.585v2.605h-2.521-3.5v-2.607l-3.586 3.587 3.586 3.586v-2.587z' fill='%23000'/%3E%3C/g%3E%3C/svg%3E`; }); } export function getFormatFromText( text: string, prevFormat: string, supportedFormats?: string[], ): string { if (supportedFormats?.includes('None') && prevFormat === '') { return ''; } if (supportedFormats?.length === 1) return supportedFormats?.[0]; if (!supportedFormats?.length || !/[a-z%]$/i.test(text)) return prevFormat || 'px'; const partialFormat = text.replace(/[^a-z%]/g, ''); const reg = new RegExp('^' + partialFormat, 'i'); return supportedFormats?.find((f) => f.match(reg)) || supportedFormats?.[0]; }