Feet-and-inches entry: type 2' 7\" instead of 2.6 (#59) (#62)
Build image / build-and-push (push) Successful in 6s
Build image / build-and-push (push) Successful in 6s
Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #62.
This commit is contained in:
@@ -4,11 +4,12 @@ import { TextField } from '@/components/ui/TextField'
|
||||
import { TextArea } from '@/components/ui/TextArea'
|
||||
import { useDeleteObject, useUpdateObject } from '@/lib/objects'
|
||||
import {
|
||||
cmFromDisplay,
|
||||
cmFromSpacing,
|
||||
dimensionUnitLabel,
|
||||
displayFromCm,
|
||||
dimensionInputMode,
|
||||
formatDimensionInput,
|
||||
MIN_DIMENSION_CM,
|
||||
parseDimension,
|
||||
spacingFromCm,
|
||||
spacingUnitLabel,
|
||||
type UnitPref,
|
||||
@@ -45,10 +46,10 @@ export function Inspector({
|
||||
// Local field state (initialized once; committed on blur/change).
|
||||
const [name, setName] = useState(object.name)
|
||||
const [notes, setNotes] = useState(object.notes)
|
||||
const [width, setWidth] = useState(String(displayFromCm(object.widthCm, unit)))
|
||||
const [height, setHeight] = useState(String(displayFromCm(object.heightCm, unit)))
|
||||
const [x, setX] = useState(String(displayFromCm(object.xCm, unit)))
|
||||
const [y, setY] = useState(String(displayFromCm(object.yCm, unit)))
|
||||
const [width, setWidth] = useState(formatDimensionInput(object.widthCm, unit))
|
||||
const [height, setHeight] = useState(formatDimensionInput(object.heightCm, unit))
|
||||
const [x, setX] = useState(formatDimensionInput(object.xCm, unit))
|
||||
const [y, setY] = useState(formatDimensionInput(object.yCm, unit))
|
||||
const [rotation, setRotation] = useState(String(Math.round(object.rotationDeg)))
|
||||
const [color, setColor] = useState(object.color ?? DEFAULT_COLOR)
|
||||
const [gridSize, setGridSize] = useState(String(spacingFromCm(object.gridSizeCm, unit)))
|
||||
@@ -62,10 +63,10 @@ export function Inspector({
|
||||
if (rootRef.current?.contains(document.activeElement)) return
|
||||
setName(object.name)
|
||||
setNotes(object.notes)
|
||||
setWidth(String(displayFromCm(object.widthCm, unit)))
|
||||
setHeight(String(displayFromCm(object.heightCm, unit)))
|
||||
setX(String(displayFromCm(object.xCm, unit)))
|
||||
setY(String(displayFromCm(object.yCm, unit)))
|
||||
setWidth(formatDimensionInput(object.widthCm, unit))
|
||||
setHeight(formatDimensionInput(object.heightCm, unit))
|
||||
setX(formatDimensionInput(object.xCm, unit))
|
||||
setY(formatDimensionInput(object.yCm, unit))
|
||||
setRotation(String(Math.round(object.rotationDeg)))
|
||||
setColor(object.color ?? DEFAULT_COLOR)
|
||||
setGridSize(String(spacingFromCm(object.gridSizeCm, unit)))
|
||||
@@ -77,14 +78,20 @@ export function Inspector({
|
||||
}
|
||||
|
||||
// Commit a dimension/position field. `positive` gates width/height (must be
|
||||
// ≥ the server minimum) but not x/y, which may be zero or negative. Compare at
|
||||
// display precision first so a blur without an edit doesn't fire a spurious
|
||||
// PATCH from cm↔ft rounding drift (e.g. 240cm shows 7.9ft → 241cm).
|
||||
// ≥ the server minimum) but not x/y, which may be zero or negative.
|
||||
//
|
||||
// The no-op guard compares the field's TEXT against the string this field
|
||||
// renders for the current value. With compound entry there is no single
|
||||
// display number left to compare, and a numeric tolerance would be worse:
|
||||
// a bed dragged to some arbitrary cm renders as, say, 2′ 7.9″, and merely
|
||||
// tabbing through the field would snap it to a whole inch. Text equality means
|
||||
// "you didn't edit this", which is what the guard is actually for. Typing the
|
||||
// same value a different way (2' 7" vs 2′ 7″) falls through to the cm compare
|
||||
// below and is still a no-op.
|
||||
const commitDim = (raw: string, current: number, apply: (cm: number) => void, positive = false) => {
|
||||
const v = parseFloat(raw)
|
||||
if (!Number.isFinite(v)) return
|
||||
if (v === displayFromCm(current, unit)) return
|
||||
const cm = cmFromDisplay(v, unit)
|
||||
if (raw.trim() === formatDimensionInput(current, unit)) return
|
||||
const cm = parseDimension(raw, unit)
|
||||
if (cm === null) return // unparseable: leave the row alone rather than commit a zero
|
||||
if (positive && cm < MIN_DIMENSION_CM) return
|
||||
if (cm !== current) apply(cm)
|
||||
}
|
||||
@@ -101,6 +108,7 @@ export function Inspector({
|
||||
}
|
||||
|
||||
const u = dimensionUnitLabel(unit)
|
||||
const inputMode = dimensionInputMode(unit)
|
||||
|
||||
return (
|
||||
<div ref={rootRef} className="flex flex-col gap-3">
|
||||
@@ -141,9 +149,8 @@ export function Inspector({
|
||||
<TextField
|
||||
label={`Width (${u})`}
|
||||
name="width"
|
||||
type="number"
|
||||
inputMode="decimal"
|
||||
step="any"
|
||||
type="text"
|
||||
inputMode={inputMode}
|
||||
value={width}
|
||||
onChange={(e) => setWidth(e.target.value)}
|
||||
onBlur={() => commitDim(width, object.widthCm, (cm) => patch({ widthCm: cm }), true)}
|
||||
@@ -151,9 +158,8 @@ export function Inspector({
|
||||
<TextField
|
||||
label={`Height (${u})`}
|
||||
name="height"
|
||||
type="number"
|
||||
inputMode="decimal"
|
||||
step="any"
|
||||
type="text"
|
||||
inputMode={inputMode}
|
||||
value={height}
|
||||
onChange={(e) => setHeight(e.target.value)}
|
||||
onBlur={() => commitDim(height, object.heightCm, (cm) => patch({ heightCm: cm }), true)}
|
||||
@@ -161,9 +167,8 @@ export function Inspector({
|
||||
<TextField
|
||||
label={`X (${u})`}
|
||||
name="x"
|
||||
type="number"
|
||||
inputMode="decimal"
|
||||
step="any"
|
||||
type="text"
|
||||
inputMode={inputMode}
|
||||
value={x}
|
||||
onChange={(e) => setX(e.target.value)}
|
||||
onBlur={() => commitDim(x, object.xCm, (cm) => patch({ xCm: cm }))}
|
||||
@@ -171,9 +176,8 @@ export function Inspector({
|
||||
<TextField
|
||||
label={`Y (${u})`}
|
||||
name="y"
|
||||
type="number"
|
||||
inputMode="decimal"
|
||||
step="any"
|
||||
type="text"
|
||||
inputMode={inputMode}
|
||||
value={y}
|
||||
onChange={(e) => setY(e.target.value)}
|
||||
onBlur={() => commitDim(y, object.yCm, (cm) => patch({ yCm: cm }))}
|
||||
|
||||
Reference in New Issue
Block a user