A single-field length input for free-form lengths with mixed units and basic math. The value is stored in metres when you leave the field or press Enter.
There is also components/live-length-input/, which is not wired up in the app. I used it to try a different way of showing parsed results; the current UI uses another approach (Rayon's style). I kept the folder instead of deleting it as a record of exploring alternate UX and UI patterns.
These choices mostly match Rayon's input behavior:
- A chain of regexes instead of a grammar or syntax tree. Keeps the code short and easy to follow.
- Clean the string first, then split it into tokens. That keeps each small parser simple.
- Commit on blur/Enter, not on every keystroke. Avoids showing errors mid-typing and keeps the reducer simple. Matches Rayon's behavior where the field only validates and formats when you leave it or press Enter.
- Append unit suffix on commit, strip on focus. After committing, the display reads e.g.
1.5 m. When the user re-focuses the field, themsuffix is removed so they edit a bare number. This avoids cursor-fighting with a trailing unit while typing. - Unknown units fall back to metres. If a user types something like
5 km, the parser does not recognizekm; thekis leftover and5 mis what matches. The number stays the same, only the unit changes. Same idea as Rayon: unknown units are treated as the default. - No parentheses or nesting. Left out on purpose to keep scope small.
- Round off tiny float errors. Simple math in metres can show values like
0.30000000000000004instead of0.3. We round to nine decimal places before display so that junk does not appear.
- Bare numbers (no unit) are treated as raw metres.
- Error messages are generic ("Invalid expression"). The tokenizer knows where it failed but does not show that to the user.
- Divide by zero does nothing (left value unchanged). When the divisor is
0, the/step is skipped and the value on the left stays the same, e.g.10 m / 0→10 m,25 / 0→25, like Rayon.
- Tests. Unit tests for each parser and the evaluate step would be the first thing to add.
- Undo / history. Let the user step back through committed values.
- Configurable output unit and precision. Select component or something similar.
- Expressions with parentheses.
- Other locales. Formatting is fixed to
en-US. Comma-as-decimal locales would break parsing. - Select all on re-focus. When the user focuses the field again (after committing or leaving it), select the entire text so the whole value is highlighted and can be replaced in one keystroke.
- One place for new units. Simple units could come from one list.
pnpm install
pnpm run dev