@itwin/presentation-components
Version:
React components based on iTwin.js Presentation library
236 lines • 10.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.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Core
*/
import { inPlaceSort } from "fast-sort";
import { PropertyRecord, StandardTypeNames, PropertyValueFormat as UiPropertyValueFormat, } from "@itwin/appui-abstract";
import { assert } from "@itwin/core-bentley";
import { combineFieldNames, PropertyValueFormat as PresentationPropertyValueFormat, } from "@itwin/presentation-common";
import { NumericEditorName } from "../properties/editors/NumericPropertyEditor.js";
import { QuantityEditorName } from "../properties/editors/QuantityPropertyEditor.js";
/** @internal */
export function createFieldInfo(field, parentFieldName) {
const property = field.isPropertiesField() ? field.properties[0].property : undefined;
return {
name: combineFieldNames(field.name, parentFieldName),
type: field.isNestedContentField() ? field.type : { ...field.type, typeName: field.type.typeName.toLowerCase() },
label: field.label,
isReadonly: field.isReadonly,
editor: field.editor,
renderer: field.renderer,
enum: property?.enumerationInfo,
koqName: property?.kindOfQuantity?.name,
constraints: property?.constraints,
};
}
/** @internal */
export function createPropertyDescriptionFromFieldInfo(info) {
const descr = {
typename: info.type.typeName,
name: info.name,
displayLabel: info.label,
};
if (info.renderer) {
descr.renderer = { name: info.renderer.name };
}
if (info.editor) {
descr.editor = { name: info.editor.name };
}
if (info.koqName) {
descr.kindOfQuantityName = info.koqName;
// eslint-disable-next-line @typescript-eslint/no-deprecated
descr.quantityType = info.koqName;
descr.editor = { name: QuantityEditorName, ...descr.editor };
}
if (info.constraints) {
descr.constraints = info.constraints;
}
if (descr.typename === StandardTypeNames.Number ||
descr.typename === StandardTypeNames.Int ||
descr.typename === StandardTypeNames.Float ||
descr.typename === StandardTypeNames.Double) {
descr.editor = { name: NumericEditorName, ...descr.editor };
}
if (info.type.valueFormat === PresentationPropertyValueFormat.Primitive && info.enum) {
descr.enum = {
choices: info.enum.choices,
isStrict: info.enum.isStrict,
};
}
return descr;
}
/** @internal */
export var IPropertiesAppender;
(function (IPropertiesAppender) {
function isRoot(appender) {
return appender.item !== undefined;
}
IPropertiesAppender.isRoot = isRoot;
function isNested(appender) {
return appender.finish !== undefined;
}
IPropertiesAppender.isNested = isNested;
})(IPropertiesAppender || (IPropertiesAppender = {}));
class StructMembersAppender {
_parentAppender;
_fieldHierarchy;
_fieldInfo;
_label;
_propertyRecordsProcessor;
_members = {};
// eslint-disable-next-line @typescript-eslint/unbound-method
_labelsComparer = new Intl.Collator(undefined, { sensitivity: "base" }).compare;
constructor(_parentAppender, _fieldHierarchy, _fieldInfo, _label, _propertyRecordsProcessor) {
this._parentAppender = _parentAppender;
this._fieldHierarchy = _fieldHierarchy;
this._fieldInfo = _fieldInfo;
this._label = _label;
this._propertyRecordsProcessor = _propertyRecordsProcessor;
}
append(record) {
this._members[record.fieldHierarchy.field.name] = record.record;
}
finish() {
const properties = Object.entries(this._members);
inPlaceSort(properties).by([{ asc: (p) => p[1].property.displayLabel, comparer: this._labelsComparer }]);
const value = {
valueFormat: UiPropertyValueFormat.Struct,
members: Object.fromEntries(properties),
};
const record = new PropertyRecord(value, createPropertyDescriptionFromFieldInfo(this._fieldInfo));
const displayLabel = this._label?.displayValue;
applyPropertyRecordAttributes(record, this._fieldHierarchy.field, displayLabel === "@Presentation:label.notSpecified@" ? undefined : displayLabel, IPropertiesAppender.isRoot(this._parentAppender) ? this._parentAppender.item.extendedData : undefined, this._propertyRecordsProcessor);
this._parentAppender.append({ record, fieldHierarchy: this._fieldHierarchy });
}
}
class ArrayItemsAppender {
_parentAppender;
_fieldHierarchy;
_fieldInfo;
_propertyRecordsProcessor;
_items = [];
constructor(_parentAppender, _fieldHierarchy, _fieldInfo, _propertyRecordsProcessor) {
this._parentAppender = _parentAppender;
this._fieldHierarchy = _fieldHierarchy;
this._fieldInfo = _fieldInfo;
this._propertyRecordsProcessor = _propertyRecordsProcessor;
}
append(record) {
this._items.push(record.record);
}
finish() {
assert(this._fieldHierarchy.field.type.valueFormat === PresentationPropertyValueFormat.Array);
const value = {
valueFormat: UiPropertyValueFormat.Array,
itemsTypeName: this._fieldHierarchy.field.type.memberType.typeName,
items: this._items,
};
const record = new PropertyRecord(value, createPropertyDescriptionFromFieldInfo(this._fieldInfo));
applyPropertyRecordAttributes(record, this._fieldHierarchy.field, undefined, IPropertiesAppender.isRoot(this._parentAppender) ? this._parentAppender.item.extendedData : undefined, this._propertyRecordsProcessor);
this._parentAppender.append({ record, fieldHierarchy: this._fieldHierarchy });
}
}
/** @internal */
export class InternalPropertyRecordsBuilder {
_appendersStack = [];
_rootAppenderFactory;
_propertyRecordsProcessor;
constructor(rootPropertiesAppenderFactory, propertyRecordsProcessor) {
this._rootAppenderFactory = rootPropertiesAppenderFactory;
this._propertyRecordsProcessor = propertyRecordsProcessor;
}
get currentPropertiesAppender() {
const appender = this._appendersStack[this._appendersStack.length - 1];
assert(appender !== undefined);
return appender;
}
startContent(_props) {
return true;
}
finishContent() { }
startItem(props) {
const appender = this._rootAppenderFactory(props.item);
this._appendersStack.push(appender);
return true;
}
finishItem() { }
processFieldHierarchies(_props) { }
startCategory(_props) {
return true;
}
finishCategory() { }
startField(_props) {
return true;
}
finishField() { }
startStruct(props) {
const fieldInfo = {
...createFieldInfo(props.hierarchy.field, props.parentFieldName),
type: props.valueType,
};
this._appendersStack.push(new StructMembersAppender(this.currentPropertiesAppender, props.hierarchy, fieldInfo, props.label, this._propertyRecordsProcessor));
return true;
}
finishStruct() {
const appender = this._appendersStack.pop();
assert(!!appender && IPropertiesAppender.isNested(appender));
appender.finish();
}
startArray(props) {
this._appendersStack.push(new ArrayItemsAppender(this.currentPropertiesAppender, props.hierarchy, {
...createFieldInfo(props.hierarchy.field, props.parentFieldName),
type: props.valueType,
}, this._propertyRecordsProcessor));
return true;
}
finishArray() {
const appender = this._appendersStack.pop();
assert(!!appender && IPropertiesAppender.isNested(appender));
appender.finish();
}
processMergedValue(props) {
const propertyField = props.requestedField;
const value = {
valueFormat: UiPropertyValueFormat.Primitive,
};
const record = new PropertyRecord(value, createPropertyDescriptionFromFieldInfo(createFieldInfo(propertyField, props.parentFieldName)));
record.isMerged = true;
record.isReadonly = true;
record.autoExpand = propertyField.isNestedContentField() && propertyField.autoExpand;
this._propertyRecordsProcessor?.(record);
this.currentPropertiesAppender.append({ record, fieldHierarchy: { field: propertyField, childFields: [] } });
}
processPrimitiveValue(props) {
const appender = this.currentPropertiesAppender;
const value = {
valueFormat: UiPropertyValueFormat.Primitive,
value: props.rawValue,
// eslint-disable-next-line @typescript-eslint/no-base-to-string
displayValue: props.displayValue?.toString() ?? "",
};
const record = new PropertyRecord(value, createPropertyDescriptionFromFieldInfo({ ...createFieldInfo(props.field, props.parentFieldName), type: props.valueType }));
applyPropertyRecordAttributes(record, props.field,
// eslint-disable-next-line @typescript-eslint/no-base-to-string
props.displayValue?.toString(), IPropertiesAppender.isRoot(appender) ? appender.item.extendedData : undefined, this._propertyRecordsProcessor);
appender.append({ record, fieldHierarchy: { field: props.field, childFields: [] } });
}
}
function applyPropertyRecordAttributes(record, field, displayValue, extendedData, propertyRecordsProcessor) {
if (displayValue) {
record.description = displayValue.toString();
}
if (field.isReadonly || (field.isNestedContentField() && record.value.valueFormat === UiPropertyValueFormat.Array)) {
record.isReadonly = true;
}
if (field.isNestedContentField() && field.autoExpand) {
record.autoExpand = true;
}
if (extendedData) {
record.extendedData = extendedData;
}
propertyRecordsProcessor?.(record);
}
//# sourceMappingURL=ContentBuilder.js.map