Refactor/reacrhitecture to fsd+ #49

Merged
ilia merged 70 commits from refactor/reacrhitecture-to-fsd+ into main 2026-06-03 09:55:47 +00:00
Showing only changes of commit 4652857512 - Show all commits
@@ -61,14 +61,6 @@ const SLIDER_SPRING_CONFIG = { stiffness: 0.2, damping: 0.7 } as const;
*/
const SLIDER_PERSIST_DEBOUNCE_MS = 100;
/**
* Horizontal layout padding subtracted from container width before laying
* out the comparison text. Different per breakpoint to match the gutters
* around the slider track.
*/
const SLIDER_PADDING_MOBILE_PX = 48;
const SLIDER_PADDING_DESKTOP_PX = 96;
/**
* Position bounds (percent of container width).
*/
@@ -94,7 +86,18 @@ const isMobile = $derived(responsive?.isMobile ?? false);
let isDragging = $state(false);
let isTypographyMenuOpen = $state(false);
/**
* Border-box width of the slider track. Drives the slider→position mapping and
* the per-char split math (pointer events are measured against this same box).
*/
let containerWidth = $state(0);
/**
* Content-box width of the slider track (border box minus the responsive CSS
* gutters). The width the text lays out into, and what the line-breaker fits
* within. Measured rather than derived from a padding constant so it tracks the
* breakpoint gutters.
*/
let contentWidth = $state(0);
const layout = new DualFontLayout();
@@ -114,10 +117,14 @@ $effect(() => {
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
// Use borderBoxSize if available, fallback to contentRect
const width = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
if (width > 0) {
containerWidth = width;
// Border box for slider/pointer math, content box for text width.
const border = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
const content = entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
if (border > 0) {
containerWidth = border;
}
if (content > 0) {
contentWidth = content;
}
}
});
@@ -226,7 +233,7 @@ $effect(() => {
}
});
// Layout effect — depends on content, settings AND containerWidth.
// Layout effect — depends on content, settings, and contentWidth.
// Awaits font loading into the canvas measurement context before invoking
// the engine; otherwise pretext caches fallback-font widths globally per
// font string, and the morph boundary drifts from the thumb visually.
@@ -236,18 +243,15 @@ $effect(() => {
const _size = typography.renderedSize;
const _height = typography.height;
const _spacing = typography.spacing;
const _width = containerWidth;
const _isMobile = isMobile;
const availableWidth = contentWidth;
if (!container || !fontA || !fontB || _width <= 0) {
if (!container || !fontA || !fontB || availableWidth <= 0) {
return;
}
const fontAStr = getPretextFontString(_weight, _size, fontA.name);
const fontBStr = getPretextFontString(_weight, _size, fontB.name);
const padding = _isMobile ? SLIDER_PADDING_MOBILE_PX : SLIDER_PADDING_DESKTOP_PX;
const availableWidth = Math.max(0, _width - padding);
const lineHeight = _size * _height;
let cancelled = false;