@itwin/presentation-components
Version:
React components based on iTwin.js Presentation library
124 lines • 6.2 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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