@itwin/presentation-components
Version:
React components based on iTwin.js Presentation library
312 lines • 11.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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncTasksTracker = exports.createLabelRecord = exports.findField = exports.getDisplayName = exports.translate = exports.localizationNamespaceName = void 0;
exports.getRulesetId = getRulesetId;
exports.useMergedRefs = useMergedRefs;
exports.useErrorState = useErrorState;
exports.useDelay = useDelay;
exports.serializeUniqueValues = serializeUniqueValues;
exports.deserializeUniqueValues = deserializeUniqueValues;
exports.memoize = memoize;
exports.createKeySetFromSelectables = createKeySetFromSelectables;
exports.mapPresentationFrontendSelectionScopeToUnifiedSelectionScope = mapPresentationFrontendSelectionScopeToUnifiedSelectionScope;
exports.safeDispose = safeDispose;
require("../common/DisposePolyfill.js");
const mm = __importStar(require("micro-memoize"));
const react_1 = require("react");
const appui_abstract_1 = require("@itwin/appui-abstract");
const core_bentley_1 = require("@itwin/core-bentley");
const presentation_common_1 = require("@itwin/presentation-common");
const presentation_frontend_1 = require("@itwin/presentation-frontend");
const unified_selection_1 = require("@itwin/unified-selection");
/** @internal */
exports.localizationNamespaceName = "PresentationComponents";
/**
* Translate a string with the specified id from `PresentationComponents`
* localization namespace. The `stringId` should not contain namespace - it's
* prepended automatically.
*
* @internal
*/
const translate = (stringId, options) => {
stringId = `${exports.localizationNamespaceName}:${stringId}`;
return presentation_frontend_1.Presentation.localization.getLocalizedString(stringId, options);
};
exports.translate = translate;
/**
* Creates a display name for the supplied component
* @internal
*/
const getDisplayName = (component) => {
if (component.displayName) {
return component.displayName;
}
if (component.name) {
return component.name;
}
return "Component";
};
exports.getDisplayName = getDisplayName;
/**
* Finds a field given the name of property record created from that field.
* @internal
*/
const findField = (descriptor, recordPropertyName) => {
let fieldsSource = descriptor;
const fieldNames = (0, presentation_common_1.parseCombinedFieldNames)(recordPropertyName);
while (fieldsSource && fieldNames.length) {
const field = fieldsSource.getFieldByName(fieldNames.shift());
fieldsSource = field && field.isNestedContentField() ? field : undefined;
if (!fieldNames.length) {
return field;
}
}
return undefined;
};
exports.findField = findField;
/**
* Creates property record for label using label definition.
* @internal
*/
const createLabelRecord = (label, name) => {
const value = {
displayValue: label.displayValue,
value: createPrimitiveLabelValue(label),
valueFormat: appui_abstract_1.PropertyValueFormat.Primitive,
};
const property = {
displayLabel: "Label",
typename: label.typeName,
name,
};
return new appui_abstract_1.PropertyRecord(value, property);
};
exports.createLabelRecord = createLabelRecord;
const createPrimitiveLabelValue = (label) => {
return presentation_common_1.LabelDefinition.isCompositeDefinition(label) ? createPrimitiveCompositeValue(label.rawValue) : label.rawValue;
};
const createPrimitiveCompositeValue = (compositeValue) => {
return {
separator: compositeValue.separator,
parts: compositeValue.values.map((part) => ({
displayValue: part.displayValue,
typeName: part.typeName,
rawValue: createPrimitiveLabelValue(part),
})),
};
};
/**
* Returns ruleset id from `RulesetOrId`.
* @internal
*/
function getRulesetId(ruleset) {
return typeof ruleset === "string" ? ruleset : ruleset.id;
}
/**
* A helper to track ongoing async tasks. Usage:
* ```
* {
* using _r = tracker.trackAsyncTask();
* await doSomethingAsync();
* }
* ```
*
* Can be used with `waitForPendingAsyncs` in test helpers to wait for all
* async tasks to complete.
*
* @internal
*/
class AsyncTasksTracker {
_asyncsInProgress = new Set();
get pendingAsyncs() {
return this._asyncsInProgress;
}
trackAsyncTask() {
const id = core_bentley_1.Guid.createValue();
this._asyncsInProgress.add(id);
return {
[Symbol.dispose]: () => this._asyncsInProgress.delete(id),
};
}
}
exports.AsyncTasksTracker = AsyncTasksTracker;
/** @internal */
/* c8 ignore start */
function useMergedRefs(...refs) {
return (0, react_1.useCallback)((instance) => {
refs.forEach((ref) => {
if (typeof ref === "function") {
ref(instance);
}
else if (ref) {
ref.current = instance;
}
});
}, [...refs]);
}
/* c8 ignore end */
/**
* A hook that helps components throw errors in React's render loop so they can be captured by React error
* boundaries.
*
* Usage: simply call the returned function with an error and it will be re-thrown in React render loop.
*
* @internal
*/
function useErrorState() {
const [_, setError] = (0, react_1.useState)(undefined);
const setErrorState = (0, react_1.useCallback)((e) => {
setError(() => {
throw e instanceof Error ? e : /* c8 ignore next */ new Error();
});
}, []);
return setErrorState;
}
/**
* A hook that rerenders component after some time.
* @param delayMilliseconds - milliseconds to delay. Default is 250.
* @internal
*/
function useDelay(delayMilliseconds = 250) {
const [passed, setPassed] = (0, react_1.useState)(false);
(0, react_1.useEffect)(() => {
const timeout = setTimeout(() => {
setPassed(true);
}, delayMilliseconds);
return () => {
clearTimeout(timeout);
};
}, [delayMilliseconds]);
return passed;
}
/**
* Function for serializing `UniqueValue`.
* Returns an object, which consists of `displayValues` and `groupedRawValues`.
*/
function serializeUniqueValues(values) {
const displayValues = [];
const groupedRawValues = {};
values.forEach((item) => {
displayValues.push(item.displayValue);
groupedRawValues[item.displayValue] = [...item.groupedRawValues];
});
return { displayValues: JSON.stringify(displayValues), groupedRawValues: JSON.stringify(groupedRawValues) };
}
/**
* Function for deserializing `displayValues` and `groupedRawValues`.
* Returns an array of `UniqueValue` or undefined if parsing fails.
*/
function deserializeUniqueValues(serializedDisplayValues, serializedGroupedRawValues) {
const tryParseJSON = (value) => {
try {
return JSON.parse(value);
}
catch {
return false;
}
};
const displayValues = tryParseJSON(serializedDisplayValues);
const groupedRawValues = tryParseJSON(serializedGroupedRawValues);
if (!displayValues || !groupedRawValues || !Array.isArray(displayValues) || Object.keys(groupedRawValues).length !== displayValues.length) {
return undefined;
}
const uniqueValues = [];
for (const displayValue of displayValues) {
uniqueValues.push({ displayValue, groupedRawValues: groupedRawValues[displayValue] });
}
return uniqueValues;
}
function memoize(fn, options) {
const microMemoize = mm.default;
return microMemoize(fn, options);
}
async function createKeySetFromSelectables(selectables) {
const keys = new presentation_common_1.KeySet();
for await (const instanceKey of unified_selection_1.Selectables.load(selectables)) {
keys.add(instanceKey);
}
return keys;
}
function mapPresentationFrontendSelectionScopeToUnifiedSelectionScope(
// eslint-disable-next-line @typescript-eslint/no-deprecated
scope) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
const scopeProps = (0, presentation_frontend_1.createSelectionScopeProps)(scope);
switch (scopeProps.id) {
case "functional-element":
return { id: "functional" };
case "functional-assembly":
return { id: "functional", ancestorLevel: 1 };
case "functional-top-assembly":
return { id: "functional", ancestorLevel: -1 };
case "element":
return { id: "element" };
case "assembly":
return { id: "element", ancestorLevel: 1 };
case "top-assembly":
return { id: "element", ancestorLevel: -1 };
case "category":
return { id: "category" };
case "model":
return { id: "model" };
}
throw new Error(`Unknown selection scope: "${scopeProps.id}"`);
}
/**
* A helper that disposes the given object, if it's disposable.
*
* The first option is to dispose using the deprecated `dispose` method if it exists on the object.
* If not, we use the new `Symbol.dispose` method. If that doesn't exist either, the object is
* considered as non-disposable and nothing is done with it.
*
* @internal
*/
function safeDispose(disposable) {
if ("dispose" in disposable) {
disposable.dispose();
}
else if (Symbol.dispose in disposable) {
disposable[Symbol.dispose]();
}
}
//# sourceMappingURL=Utils.js.map