UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

124 lines 6.2 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { useEffect, useRef, useState } from "react"; import { assert } from "@itwin/core-bentley"; import { IModelApp } from "@itwin/core-frontend"; import { FormatType } from "@itwin/core-quantity"; import { KoqPropertyValueFormatter } from "@itwin/presentation-common"; import { applyNumericConstraints, getMinMaxFromPropertyConstraints, getPersistenceUnitRoundingError } from "./Utils.js"; /** * Custom hook that manages state for quantity values input. * @internal */ export function useQuantityValueInput({ initialRawValue, schemaContext, koqName, constraints, }) { const initialRawValueRef = useRef(initialRawValue); const [{ quantityValue, placeholder }, setState] = useState(() => ({ quantityValue: { rawValue: initialRawValueRef.current, highPrecisionFormattedValue: "", defaultFormattedValue: "", roundingError: undefined, }, placeholder: "", })); const onFormatterLoad = useRef(({ newHighPrecisionFormatter, newParser, newDefaultFormatter }) => { setState((prev) => { /* v8 ignore next 1 -- @preserve */ const defaultValue = prev.quantityValue.rawValue !== undefined ? newDefaultFormatter.applyFormatting(prev.quantityValue.rawValue) : `-- ${newHighPrecisionFormatter.unitConversions[0].label}`; const newFormattedValue = prev.quantityValue.rawValue !== undefined ? newHighPrecisionFormatter.applyFormatting(prev.quantityValue.rawValue) : newHighPrecisionFormatter.unitConversions[0].label; const placeholderUnit = newHighPrecisionFormatter.unitConversions[0].label; const roundingError = getPersistenceUnitRoundingError(newFormattedValue, newParser); return { ...prev, quantityValue: { ...prev.quantityValue, highPrecisionFormattedValue: newFormattedValue, defaultFormattedValue: defaultValue, roundingError, }, placeholder: placeholderUnit, }; }); }); const useFormatterAndParserResult = useFormatterAndParser(koqName, schemaContext, onFormatterLoad.current); const onChange = (e) => { assert(useFormatterAndParserResult !== undefined); // input should be disabled if parser is `undefined` const { parser, defaultFormatter } = useFormatterAndParserResult; const newValue = e.currentTarget.value; const parseResult = parser.parseToQuantityValue(newValue); const roundingError = getPersistenceUnitRoundingError(newValue, parser); const defaultFormattedValue = parseResult.ok ? defaultFormatter?.applyFormatting(parseResult.value) : undefined; const rawValue = parseResult.ok ? applyNumericConstraints({ ...getMinMaxFromPropertyConstraints(constraints), value: parseResult.value }) : undefined; setState((prev) => ({ ...prev, quantityValue: { highPrecisionFormattedValue: newValue, defaultFormattedValue: defaultFormattedValue ?? newValue, rawValue, roundingError: parseResult.ok ? roundingError : undefined, }, })); }; return { quantityValue, inputProps: { onChange, placeholder, disabled: !useFormatterAndParserResult } }; } function useFormatterAndParser(koqName, schemaContext, onChange) { const [state, setState] = useState(); useEffect(() => { const findFormatterAndParser = async () => { // eslint-disable-next-line @typescript-eslint/no-deprecated const koqFormatter = new KoqPropertyValueFormatter(schemaContext, undefined, IModelApp.formatsProvider); const highPrecisionFormatter = await koqFormatter.getFormatterSpec({ koqName, unitSystem: IModelApp.quantityFormatter.activeUnitSystem, }); // formatter for default value should not have precision override const defaultFormatter = await koqFormatter.getFormatterSpec({ koqName, unitSystem: IModelApp.quantityFormatter.activeUnitSystem, }); const parserSpec = await koqFormatter.getParserSpec({ koqName, unitSystem: IModelApp.quantityFormatter.activeUnitSystem, }); if (highPrecisionFormatter && parserSpec && defaultFormatter) { if (highPrecisionFormatter.format.type === FormatType.Decimal) { highPrecisionFormatter.format.precision = 12; } onChange({ newHighPrecisionFormatter: highPrecisionFormatter, newParser: parserSpec, newDefaultFormatter: defaultFormatter, }); setState({ highPrecisionFormatter, parserSpec, defaultFormatter }); return; } setState(undefined); }; void findFormatterAndParser(); const listeners = [ IModelApp.quantityFormatter.onActiveFormattingUnitSystemChanged.addListener(findFormatterAndParser), ]; if (IModelApp.formatsProvider) { listeners.push(IModelApp.formatsProvider.onFormatsChanged.addListener(findFormatterAndParser)); } return () => { listeners.forEach((listener) => listener()); }; }, [koqName, schemaContext, onChange]); return state ? { highPrecisionFormatter: state.highPrecisionFormatter, parser: state.parserSpec, defaultFormatter: state.defaultFormatter, } : undefined; } //# sourceMappingURL=UseQuantityValueInput.js.map