UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

236 lines 10.2 kB
/*--------------------------------------------------------------------------------------------- * 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