web: the histogram waits to be asked for, the phone's ruler is a finger tall, and its x answers a real press — a 22px strip under a 44px thumb, a histogram that opened over the photo, and a close button whose press the drag's own preventDefault ate

This commit is contained in:
2026-10-01 09:00:56 +07:00
parent 31435aac77
commit fd330c05e0
3 changed files with 17 additions and 4 deletions
+10 -1
View File
@@ -1719,8 +1719,17 @@ input[type="range"] { width: 100%; accent-color: var(--accent); }
.col[data-col="slider"] input[type="range"] {
-webkit-appearance: none;
appearance: none;
height: 22px;
/* A finger is wider than the ruler. The strip the ticks are drawn on is
22px tall, and a thumb that lands a dozen pixels off its centre is on the
photo above it or the row below — the drag never begins. The input's own
box is the target, so it grows to the finger; the track inside it keeps
the 22px the ruler is read at, because the pseudo-elements below set that
height themselves. touch-action none because the drag belongs to the
knob: nothing here may be taken for a scroll, a pull-to-refresh or a
URL-bar slide instead, and this row sits where those begin. */
height: 44px;
background: none;
touch-action: none;
}
/* One rule per engine: a grouped selector that names a pseudo-element the
engine does not know — `-moz-range-track` in Chromium — is dropped whole,
+4
View File
@@ -250,6 +250,10 @@ export function Histogram({ url, onClose }: { url: string; onClose: () => void }
const start = (e: React.PointerEvent<HTMLDivElement>) => {
if (e.button !== 0) return;
// The × sits in this head but is a button, not a grip: preventDefault here
// swallows the click that follows the press (measured — a real click on it
// did nothing, while el.click() worked), so the press is left to it.
if ((e.target as HTMLElement).closest('.hist-close')) return;
e.preventDefault();
e.stopPropagation();
e.currentTarget.setPointerCapture(e.pointerId);
+3 -3
View File
@@ -419,9 +419,9 @@ export function ImageStage({
// 0.5 is the middle of the photo, which is where the bar starts.
const [split, setSplit] = useState(0.5);
const draggingSplit = useRef(false);
// The histogram overlay is shown by default and dismissed from its own frame
// or from the toolbar button; it steps aside while the crop frame is up.
const [showHist, setShowHist] = useState(true);
// The histogram overlay is closed when the studio opens and raised from the
// toolbar button or from its own frame; it steps aside while the crop frame is up.
const [showHist, setShowHist] = useState(false);
// Where the eyedropper's own icon is drawing itself: a fraction of the photo,
// which is what the layer is, so the stage's zoom cannot scale the offset a
// second time and leave the icon drifting away from the cursor.