Skip to content

Commit

Permalink
Fix convert input handling
Browse files Browse the repository at this point in the history
  • Loading branch information
kuchta committed Oct 29, 2023
1 parent 2657613 commit 980b3f1
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 19 deletions.
59 changes: 43 additions & 16 deletions src/components/Convert.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, memo, useEffect } from 'react'
import React, { useState, memo, useEffect, useRef } from 'react'

import { Radix, num2str, str2num, areRadixesEqual } from '../utils'

Expand All @@ -7,8 +7,10 @@ function Convert({ radixes }: { radixes: Radix[] }) {
const [ value, setValue ] = useState(0n)

const keyDown = (e: KeyboardEvent) => {
// console.log('keyDown:', e)
switch (e.key) {
case '0': setValue(0n); break
case 'Backspace':
case 'Delete': setValue(0n); break
case '+':
case '=': setValue(v => v + 1n); break
case '-':
Expand Down Expand Up @@ -62,19 +64,41 @@ function NumberContainer({ value, radix, radixIndex, numRadixes, updateValue }:
updateValue: (v: bigint) => void
}) {
const [ v, setV ] = useState(num2str(value, radix))
const ref = useRef<HTMLSpanElement>(null)
const [ position, setPosition ] = useState<number>()

useEffect(() => setV(num2str(value, radix)), [ value, radix ])
useEffect(() => {
if (position == undefined) {
setV(num2str(value, radix))
}
}, [ value, radix ])

useEffect(() => {
if (position != undefined && ref.current) {
setCaretPosition(ref.current, position)
}
}, [ v ])

const handleInput: React.FormEventHandler<HTMLSpanElement> = e => {
e.stopPropagation()

const s = e.currentTarget.innerText.trim().toUpperCase()
if (s === '') return

let position = getCaretPosition()
try {
const s = e.currentTarget.innerText.trimEnd().toUpperCase()
const n = str2num(s, radix)
setV(s)
updateValue(n)
} catch (error) {
console.error(error)
e.currentTarget.innerText = v
if (position && ref.current) {
position -= 1
setCaretPosition(ref.current, position)
}
}
moveCursorToEnd(e.currentTarget)
setPosition(position)
}

return <>
Expand All @@ -83,8 +107,10 @@ function NumberContainer({ value, radix, radixIndex, numRadixes, updateValue }:
tabIndex={1}
contentEditable={true}
suppressContentEditableWarning={true}
onInput={handleInput}
spellCheck={false}
onInput={handleInput}
onBlur={() => setPosition(undefined)}
ref={ref}
style={{ color: `hsl(${radixIndex / numRadixes * 300} 80% 40%)` }}
>
{v}
Expand All @@ -108,15 +134,16 @@ function shr(value: bigint, radix: Radix) {
return str2num(num2str(value, radix).slice(0, -1), radix)
}

function moveCursorToEnd(ref: Node) {
if (window.getSelection && document.createRange) {
const range = document.createRange()
range.selectNodeContents(ref)
range.collapse(false)
const sel = window.getSelection()
if (sel) {
sel.removeAllRanges()
sel.addRange(range)
}
function getCaretPosition() {
const sel = window.getSelection()
if (sel) {
return sel.getRangeAt(0).startOffset
}
}

function setCaretPosition(node: Node, position: number) {
const sel = window.getSelection()
if (sel) {
sel.setPosition(node.childNodes[0], position)
}
}
11 changes: 8 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type Radix = {
system: 'standard' | 'bijective' | 'balanced' | 'my'
radix: bigint
chars: string[]
zeroAt: number
low: number
high: number
enabled: boolean
Expand Down Expand Up @@ -96,6 +97,7 @@ export function createRadix(radix: number, system: Radix["system"], chars = defa
system: 'standard',
radix: BigInt(radix),
chars: radix === 27 && chars === defaultCharsArray ? s2a(base27) : chars.slice(zeroAt, zeroAt + radix),
zeroAt: 0,
low: 0,
high: radix - 1,
enabled: enabled != undefined ? enabled : [ 2, 3, 6, 9, 10, 12, 19, 27 ].includes(radix)
Expand All @@ -107,6 +109,7 @@ export function createRadix(radix: number, system: Radix["system"], chars = defa
system: 'bijective',
radix: BigInt(radix),
chars: radix === 26 && chars === defaultCharsArray ? s2a(bijBase26) : chars.slice(zeroAt, zeroAt + radix + 1),
zeroAt: 0,
low: 1,
high: radix,
enabled: enabled != undefined ? enabled : [ 6, 9, 10, 26 ].includes(radix),
Expand All @@ -118,6 +121,7 @@ export function createRadix(radix: number, system: Radix["system"], chars = defa
system: 'balanced',
radix: BigInt(radix),
chars: radix === 27 && chars === defaultCharsArray ? s2a(balBase27) : chars.slice(zeroAt - half, zeroAt + half + 1),
zeroAt: half,
low: -half,
high: half,
enabled: enabled != undefined ? enabled : [ 3, 9, 19, 27 ].includes(radix),
Expand All @@ -129,6 +133,7 @@ export function createRadix(radix: number, system: Radix["system"], chars = defa
system: 'my',
radix: BigInt(radix),
chars: chars.slice(zeroAt - half + 1, zeroAt + half + 1),
zeroAt: half - 1,
low: -half + 1,
high: half,
enabled: enabled != undefined ? enabled : [ 2, 4, 6, 8, 10, 12, 18, 20, 26, 28 ].includes(radix),
Expand All @@ -144,7 +149,7 @@ export function areRadixesEqual({ radixes: oldRadixes }: { radixes: Radix[] }, {
const ret = oldRadixes.length === newRadixes.length
&& oldRadixes.every((radix, i) => radix.name === newRadixes[i].name
&& radix.chars.every((char, j) => char === newRadixes[i].chars[j]))
// console.log(`areRadixesEqual(${tab}): `, ret)
// console.log(`areRadixesEqual(${tab}):`, ret)
return ret
}

Expand Down Expand Up @@ -189,7 +194,7 @@ export function num2str(num: bigint, radix: Radix): string {
}

export function str2num(str: string, radix: Radix): bigint {
if (str === '0') {
if (str === radix.chars[radix.zeroAt]) {
return 0n
}

Expand All @@ -203,7 +208,7 @@ export function str2num(str: string, radix: Radix): bigint {

const n = Array.from(s).reduce((acc, d) => {
const v = chars.indexOf(d)
if (v < (bij ? 1 : 0)) throw new Error(`str2num(${str}, ${radix.chars}): Unrecognized digit character: ${d}`)
if (v < (bij ? 1 : 0)) throw new Error(`str2num("${str}", "${radix.chars.join('')}"): Unrecognized digit character: "${d}"`)
acc = acc * r + BigInt((bal ? low : 0) + v)
return acc
}, 0n)
Expand Down

0 comments on commit 980b3f1

Please sign in to comment.