Hacky demo changes

This commit is contained in:
Andras Schmelczer 2026-05-06 19:36:04 +01:00
parent 7cba369308
commit ea7afd618c
39 changed files with 2041 additions and 745 deletions

View file

@ -0,0 +1,58 @@
import { describe, expect, it } from 'vitest';
import { canWheelScrollInsideTarget } from './dom-scroll';
function setElementMetrics(
element: HTMLElement,
metrics: Partial<{
clientHeight: number;
clientWidth: number;
scrollHeight: number;
scrollWidth: number;
}>
) {
for (const [key, value] of Object.entries(metrics)) {
Object.defineProperty(element, key, { configurable: true, value });
}
}
describe('canWheelScrollInsideTarget', () => {
it('allows horizontal wheel gestures inside a horizontal scroller', () => {
const scroller = document.createElement('div');
scroller.style.overflowX = 'auto';
scroller.scrollLeft = 20;
setElementMetrics(scroller, { clientWidth: 100, scrollWidth: 240 });
const child = document.createElement('button');
scroller.appendChild(child);
document.body.appendChild(scroller);
expect(canWheelScrollInsideTarget(child, 40, 0)).toBe(true);
scroller.remove();
});
it('allows vertical wheel gestures inside a vertical scroller', () => {
const scroller = document.createElement('div');
scroller.style.overflowY = 'auto';
scroller.scrollTop = 20;
setElementMetrics(scroller, { clientHeight: 100, scrollHeight: 240 });
const child = document.createElement('button');
scroller.appendChild(child);
document.body.appendChild(scroller);
expect(canWheelScrollInsideTarget(child, 60, 20)).toBe(true);
scroller.remove();
});
it('does not allow horizontal gestures at the edge of a scroller', () => {
const scroller = document.createElement('div');
scroller.style.overflowX = 'auto';
scroller.scrollLeft = 0;
setElementMetrics(scroller, { clientWidth: 100, scrollWidth: 240 });
document.body.appendChild(scroller);
expect(canWheelScrollInsideTarget(scroller, -40, 0)).toBe(false);
scroller.remove();
});
});

View file

@ -0,0 +1,45 @@
const SCROLLABLE_OVERFLOW = new Set(['auto', 'scroll', 'overlay']);
function canScrollHorizontally(element: HTMLElement, deltaX: number): boolean {
if (deltaX === 0) return false;
const style = window.getComputedStyle(element);
if (!SCROLLABLE_OVERFLOW.has(style.overflowX)) return false;
if (element.scrollWidth <= element.clientWidth) return false;
const maxScrollLeft = element.scrollWidth - element.clientWidth;
if (deltaX < 0) return element.scrollLeft > 0;
return element.scrollLeft < maxScrollLeft - 1;
}
function canScrollVertically(element: HTMLElement, deltaY: number): boolean {
if (deltaY === 0) return false;
const style = window.getComputedStyle(element);
if (!SCROLLABLE_OVERFLOW.has(style.overflowY)) return false;
if (element.scrollHeight <= element.clientHeight) return false;
const maxScrollTop = element.scrollHeight - element.clientHeight;
if (deltaY < 0) return element.scrollTop > 0;
return element.scrollTop < maxScrollTop - 1;
}
export function canWheelScrollInsideTarget(
target: EventTarget | null,
deltaX: number,
deltaY: number
): boolean {
let element = target instanceof Element ? target : null;
while (element && element !== document.body && element !== document.documentElement) {
if (
element instanceof HTMLElement &&
(canScrollHorizontally(element, deltaX) || canScrollVertically(element, deltaY))
) {
return true;
}
element = element.parentElement;
}
return false;
}

View file

@ -19,6 +19,12 @@ const FEATURE_ICON_PATHS: Record<string, ReactNode> = {
<polyline points="15 6 21 6 21 12" />
</>
),
'Estimated price': (
<>
<polyline points="4 16 8 12 13 15 20 6" />
<polyline points="15 6 21 6 21 12" />
</>
),
'Price per sqm': (
<>
<rect x="3" y="3" width="7" height="7" />
@ -109,6 +115,18 @@ const FEATURE_ICON_PATHS: Record<string, ReactNode> = {
<line x1="12" y1="18" x2="12" y2="15" />
</>
),
'Travel time to nearest train or tube station (min)': (
<>
<rect x="5" y="3" width="14" height="10" rx="2" />
<path d="M8 17h8" />
<path d="M9 13l-2 4" />
<path d="M15 13l2 4" />
<circle cx="8.5" cy="8" r="1" fill="currentColor" />
<circle cx="15.5" cy="8" r="1" fill="currentColor" />
<path d="M12 18v3" />
<circle cx="12" cy="21" r="1.5" />
</>
),
// ── Education ────────────────────────────────
'Education, Skills and Training Score': (