Themes(toilets): add an allowed range to some freeform inputs, allow to specify 'units' in the freeform, add the possibility to convert units

This commit is contained in:
Pieter Vander Vennet 2025-05-20 00:34:39 +02:00
parent 32cb8f489f
commit fb8ead2a2c
16 changed files with 270 additions and 103 deletions

View file

@ -4,12 +4,17 @@
import Validators from "./Validators"
import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid"
import { Translation } from "../i18n/Translation"
import { createEventDispatcher, onDestroy } from "svelte"
import { Validator } from "./Validator"
import { Unit } from "../../Models/Unit"
import UnitInput from "../Popup/UnitInput.svelte"
import { Utils } from "../../Utils"
import { twMerge } from "tailwind-merge"
import type { ValueRange } from "../../Models/ThemeConfig/TagRenderingConfig"
import Translations from "../i18n/Translations"
import FloatValidator from "./Validators/FloatValidator"
import BaseUIElement from "../BaseUIElement"
export let type: ValidatorType
export let feedback: UIEventSource<Translation> | undefined = undefined
@ -18,6 +23,7 @@
export let placeholder: string | Translation | undefined = undefined
export let autofocus: boolean = false
export let unit: Unit = undefined
export let range: ValueRange = undefined
/**
* Valid state, exported to the calling component
*/
@ -42,7 +48,7 @@
function initValueAndDenom() {
if (unit && value.data) {
const [v, denom] = unit?.findDenomination(value.data, getCountry)
const [v, denom] = unit.findDenomination(value.data, getCountry)
if (denom) {
unvalidatedText.setData(v)
selectedUnit.setData(denom.canonical)
@ -62,7 +68,6 @@
}
}
initValueAndDenom()
$: {
// The type changed -> reset some values
validator = Validators.get(type ?? "string")
@ -77,6 +82,41 @@
initValueAndDenom()
}
const t = Translations.t.validation.generic
/**
* Side effect: sets the feedback, returns true/false if valid
* @param canonicalValue
*/
function validateRange(canonicalValue: number): boolean {
if (!range) {
return true
}
if (canonicalValue < range.warnBelow) {
feedback.set(t.suspiciouslyLow)
}
if (canonicalValue > range.warnAbove) {
feedback.set(t.suspiciouslyHigh)
}
if (canonicalValue > range.max) {
let max: number | string | BaseUIElement = range.max
if (unit) {
max = unit.asHumanLongValue(max)
}
feedback.set(t.tooHigh.Subs({ max }))
return false
}
if (canonicalValue < range.min) {
let min: number | string | BaseUIElement = range.min
if (unit) {
min = unit.asHumanLongValue(min)
}
feedback.set(t.tooLow.Subs({ min }))
return false
}
return true
}
function setValues() {
// Update the value stores
const v = unvalidatedText.data
@ -92,13 +132,22 @@
}
if (selectedUnit.data) {
value.setData(unit.toOsm(v, selectedUnit.data))
const canonicalValue = unit.valueInCanonical(v + selectedUnit.data)
if (validateRange(canonicalValue)) {
value.setData(unit.toOsm(v, selectedUnit.data))
} else {
value.set(undefined)
}
} else {
value.setData(v)
if (validateRange(v)) {
value.setData(v)
} else {
value.set(undefined)
}
}
}
onDestroy(unvalidatedText.addCallbackAndRun((_) => setValues()))
onDestroy(unvalidatedText.addCallbackAndRun(() => setValues()))
if (unit === undefined) {
onDestroy(
value.addCallbackAndRunD((fromUpstream) => {
@ -110,7 +159,7 @@
} else {
// Handled by the UnitInput
}
onDestroy(selectedUnit.addCallback((_) => setValues()))
onDestroy(selectedUnit.addCallback(() => setValues()))
if (validator === undefined) {
throw (
"Not a valid type (no validator found) for type '" +