Files
edr-platform/apps/edr-freight-web/backoffice/src/user-management/TemplateSample/TemplateSampleForm.utils.ts
natib21 e6e44e773b fix ui
2026-07-10 11:25:59 +00:00

106 lines
3.3 KiB
TypeScript

/**
* Pure CSS utility functions for TemplateSampleForm.
* Extracted here to keep the main form component under 300 lines.
*/
/** Normalize list-style CSS properties — preserves special values like disclosure-closed */
export function normalizeListStyleProps(
obj: Record<string, string>,
): Record<string, string> {
const normalized = { ...obj };
const specialListStyles = ["disclosure-closed", "disclosure-open", "none"];
if (normalized["list-style"]) {
const listStyleValue = normalized["list-style"].split(" ")[0];
if (specialListStyles.includes(listStyleValue)) {
delete normalized["list-style-type"];
return normalized;
}
if (!normalized["list-style-type"]) {
normalized["list-style-type"] = listStyleValue;
}
}
if (normalized["list-style-type"] && !normalized["list-style"]) {
normalized["list-style"] = normalized["list-style-type"];
}
return normalized;
}
/** Serialize a style object to a CSS declaration string */
export function styleObjectToCss(style: Record<string, unknown>): string {
return Object.entries(style)
.filter(([, v]) => v !== null && v !== undefined && v !== "null" && v !== "")
.map(([k, v]) => `${k}: ${String(v)};`)
.join(" ");
}
/**
* Parse CSS declarations from a string, correctly handling data URIs
* (colons and semicolons inside url(...) are not treated as delimiters).
*/
export function parseCSSDeclarations(cssString: string): Array<[string, string]> {
const results: Array<[string, string]> = [];
let depth = 0;
let current = "";
for (let i = 0; i < cssString.length; i++) {
const ch = cssString[i];
if (ch === "(") depth++;
else if (ch === ")") depth--;
if (ch === ";" && depth === 0) {
current = current.trim();
if (current) {
const colonIdx = current.indexOf(":");
if (colonIdx > 0) {
const prop = current.slice(0, colonIdx).trim();
const val = current.slice(colonIdx + 1).trim();
if (prop && val) results.push([prop, val]);
}
}
current = "";
} else {
current += ch;
}
}
// Handle last declaration with no trailing semicolon
current = current.trim();
if (current) {
const colonIdx = current.indexOf(":");
if (colonIdx > 0) {
const prop = current.slice(0, colonIdx).trim();
const val = current.slice(colonIdx + 1).trim();
if (prop && val) results.push([prop, val]);
}
}
return results;
}
/** Convert a CSS string to a normalized style object (data-URI safe) */
export function cssStringToObject(cssString: string): Record<string, string> {
const obj: Record<string, string> = {};
parseCSSDeclarations(cssString).forEach(([prop, val]) => {
obj[prop] = val;
});
return normalizeListStyleProps(obj);
}
/** Convert a simple CSS string to a style object (no data-URI support) */
export function parseCSSStringToObject(cssString: string): Record<string, string> {
const obj: Record<string, string> = {};
cssString
.split(";")
.filter((d) => d.trim())
.forEach((declaration) => {
const [property, value] = declaration.split(":").map((s) => s.trim());
if (property && value) {
obj[property] = value;
}
});
return normalizeListStyleProps(obj);
}