UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

312 lines 11.2 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * 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