import { compose, castArray, parseFloat as parseFloat$1, matchPercent } from '@react-pdf/fns'; import matchMedia from 'media-engine'; import hlsToHex from 'hsl-to-hex'; import colorString from 'color-string'; import parse$1 from 'postcss-value-parser/lib/parse.js'; import parseUnit from 'postcss-value-parser/lib/unit.js'; /** * Remove nil values from array * * @param array - Style array * @returns Style array without nils */ const compact = (array) => array.filter((item) => item != null); /** * Merges style objects array * * @param styles - Style array * @returns Merged style object */ const mergeStyles = (styles) => styles.reduce((acc, style) => { const s = Array.isArray(style) ? flatten(style) : style; if (!s) return acc; for (const key of Object.keys(s)) { if (s[key] != null) { acc[key] = s[key]; } } return acc; }, {}); /** * Flattens an array of style objects, into one aggregated style object. * Supports nested arrays of styles. * * @param styles - Style or style array (can be nested) * @returns Flattened style object */ const flatten = compose(mergeStyles, compact, (castArray)); /** * Resolves media queries in styles object * * @param container - Container for which styles are resolved * @param style - Style description * @returns Resolved style object */ const resolveMediaQueries = (container, style) => { return Object.entries(style).reduce((acc, [key, value]) => { if (key.startsWith('@media')) { return { ...acc, ...matchMedia({ [key]: value }, container) }; } return { ...acc, [key]: value }; }, {}); }; const isRgb = (value) => /^rgba?\(/i.test(value); const isHsl = (value) => /^hsla?\(/i.test(value); /** * Transform rgb color to hexa * * @param value - Styles value * @returns Transformed value */ const parseRgb = (value) => { const rgb = colorString.get.rgb(value); if (!rgb) return value; return colorString.to.hex(rgb[0], rgb[1], rgb[2], rgb[3]); }; /** * Transform Hsl color to hexa * * @param value - Styles value * @returns Transformed value */ const parseHsl = (value) => { const hsl = colorString.get.hsl(value); if (!hsl) return value; const [h, s, l, a] = hsl; const hex = hlsToHex(Math.round(h), Math.round(s), Math.round(l)); // Append alpha channel if not fully opaque if (a !== undefined && a < 1) { const alphaHex = Math.round(a * 255) .toString(16) .toUpperCase() .padStart(2, '0'); return hex.toUpperCase() + alphaHex; } return hex.toUpperCase(); }; /** * Transform given color to hexa * * @param value - Styles value * @returns Transformed value */ const transformColor = (value) => { const trimmed = value?.trim(); if (isRgb(trimmed)) return parseRgb(trimmed); if (isHsl(trimmed)) return parseHsl(trimmed); return trimmed; }; const VALUE_REGEX = /^(-?\d*\.?\d+)(in|mm|cm|pt|vh|vw|px|rem)?$/; const DEFAULT_DPI = 72; const DEFAULT_REM_BASE = 18; const MM_PER_INCH = 25.4; const CM_PER_INCH = 2.54; /** * Parses scalar value in value and unit pairs * * @param value - Scalar value * @returns Parsed value */ const parseValue = (value) => { if (typeof value === 'number') return { value, unit: undefined }; const match = VALUE_REGEX.exec(value); return match ? { value: parseFloat(match[1]), unit: (match[2] || 'pt') } : { value, unit: undefined }; }; /** * Transform given scalar value to points * * @param container - Container with dimensions and settings * @param value - Styles value * @returns Transformed value in points */ const transformUnit = (container, value) => { const scalar = parseValue(value); if (typeof scalar.value !== 'number') return scalar.value; const inputDpi = container.dpi || DEFAULT_DPI; switch (scalar.unit) { case 'rem': return scalar.value * (container.remBase || DEFAULT_REM_BASE); case 'in': return scalar.value * DEFAULT_DPI; case 'mm': return scalar.value * (DEFAULT_DPI / MM_PER_INCH); case 'cm': return scalar.value * (DEFAULT_DPI / CM_PER_INCH); case 'vh': return scalar.value * (container.height / 100); case 'vw': return scalar.value * (container.width / 100); case 'px': return Math.round(scalar.value * (DEFAULT_DPI / inputDpi)); default: return scalar.value; } }; const processNumberValue = (key, value) => ({ [key]: parseFloat$1(value), }); const processUnitValue = (key, value, container) => ({ [key]: transformUnit(container, value), }); const processColorValue = (key, value) => { const result = { [key]: transformColor(value) }; return result; }; const processNoopValue = (key, value) => ({ [key]: value, }); // Matches border shorthand: "width style color" (e.g., "1px solid red") const BORDER_SHORTHAND_REGEX = /^(?-?\d+(?:\.\d+)?(?:in|mm|cm|pt|vw|vh|px|rem)?)\s+(?