Files
odysseus/static/js/editor/gradient-stops.js
T

64 lines
1.9 KiB
JavaScript

/** Shared normalization for editable linear-gradient stops. */
export const MAX_GRADIENT_STOPS = 12;
function finite(value, fallback, min, max) {
const parsed = Number(value);
return Number.isFinite(parsed) ? Math.max(min, Math.min(max, parsed)) : fallback;
}
function color(value, fallback) {
const text = String(value || '').trim();
return text || fallback;
}
export function legacyGradientStops({
start = '#ffffff',
mid = '#808080',
midEnabled = false,
midPosition = 50,
end = '#000000',
} = {}) {
const stops = [{ position: 0, color: color(start, '#ffffff') }];
if (midEnabled) {
stops.push({
position: finite(midPosition, 50, 1, 99),
color: color(mid, '#808080'),
});
}
stops.push({ position: 100, color: color(end, '#000000') });
return stops;
}
export function normalizeGradientStops(value, legacy = {}) {
const source = Array.isArray(value) && value.length ? value : legacyGradientStops(legacy);
const stops = source.map((stop, index) => ({
position: finite(stop?.position, index === 0 ? 0 : 100, 0, 100),
color: color(stop?.color, index === 0 ? '#ffffff' : '#000000'),
}));
stops.sort((a, b) => a.position - b.position);
const unique = [];
for (const stop of stops) {
const previous = unique.at(-1);
if (previous && Math.abs(previous.position - stop.position) < 0.0001) {
unique[unique.length - 1] = stop;
} else {
unique.push(stop);
}
}
if (!unique.length || unique[0].position > 0) {
unique.unshift({ position: 0, color: unique[0]?.color || '#ffffff' });
} else {
unique[0].position = 0;
}
if (unique.at(-1).position < 100) {
unique.push({ position: 100, color: unique.at(-1)?.color || '#000000' });
} else {
unique.at(-1).position = 100;
}
const first = unique[0];
const last = unique.at(-1);
return [first, ...unique.slice(1, -1).slice(0, MAX_GRADIENT_STOPS - 2), last];
}