@babylonjs/inspector 8.49.6 → 8.49.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,17 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { createContext, forwardRef, useContext, useState, useCallback, Component, useMemo, useEffect, useRef, isValidElement, cloneElement, Children, useLayoutEffect, useImperativeHandle, createElement, Suspense, memo, Fragment as Fragment$1, useReducer, lazy } from 'react';
3
- import { tokens, makeStyles, Tooltip as Tooltip$1, Button as Button$1, Spinner, Link as Link$1, Caption1, Body1, ToggleButton as ToggleButton$1, useFluent, InfoLabel as InfoLabel$1, mergeClasses, Body1Strong, useId, useToastController, Toast, ToastBody, FluentProvider, Toaster, Checkbox as Checkbox$1, Accordion as Accordion$1, AccordionItem, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Portal, RendererProvider, createDOMRenderer, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, treeItemLevelToken, SearchBox as SearchBox$1, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, MenuItemCheckbox, Switch as Switch$1, SpinButton as SpinButton$1, Input, Dropdown as Dropdown$1, Option, Popover as Popover$1, PopoverTrigger, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch, PresenceBadge, Slider, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, Badge, Label, MessageBar as MessageBar$1, MessageBarBody, MessageBarTitle, Subtitle2, useComboboxFilter, Combobox, Textarea as Textarea$1, ToolbarButton, ToolbarDivider, Field } from '@fluentui/react-components';
4
- import { ErrorCircleRegular, ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, CopyRegular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, DocumentTextRegular, createFluentIcon, FilterRegular, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, SettingsRegular, ArrowUploadRegular, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, WeatherSunnyRegular, WeatherMoonRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, AddRegular, DeleteRegular, FullScreenMaximizeRegular, ChevronDownRegular, ChevronRightRegular, CircleSmallFilled, SaveRegular, PreviousRegular, ArrowPreviousRegular, TriangleLeftRegular, RecordStopRegular, PlayRegular, ArrowNextRegular, NextRegular, EditRegular, PauseRegular, LinkDismissRegular, LinkEditRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, EyeRegular, CloudArrowUpRegular, CloudArrowDownRegular, EyeOffFilled, EyeFilled, ArrowMoveFilled, StopFilled, PlayFilled, EyeOffRegular, LockOpenRegular, LockClosedRegular, ResizeRegular, ChevronUpRegular, ArrowResetRegular, CircleHalfFillRegular, EyedropperRegular, PaintBucketRegular, InkStrokeRegular, StackRegular, FilmstripRegular, PauseFilled, WeatherSunnyLowFilled, LayerRegular, FrameRegular, AppGenericRegular, RectangleLandscapeRegular, BorderOutsideRegular, BorderNoneRegular, MyLocationRegular, CameraRegular, LightbulbRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, SoundWaveCircleRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, PersonFeedbackRegular, BranchRegular, DeleteFilled } from '@fluentui/react-icons';
2
+ import { createContext, forwardRef, useContext, useState, useCallback, Component, useMemo, useEffect, useRef, useReducer, Children, isValidElement, useLayoutEffect, cloneElement, useImperativeHandle, createElement, Suspense, memo, Fragment as Fragment$1, lazy } from 'react';
3
+ import { tokens, makeStyles, Tooltip as Tooltip$1, Button as Button$1, Spinner, Accordion as Accordion$1, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, MessageBar as MessageBar$1, MessageBarBody, AccordionItem, SearchBox as SearchBox$1, Portal, Link as Link$1, Caption1, Body1, ToggleButton as ToggleButton$1, useFluent, InfoLabel as InfoLabel$1, mergeClasses, Body1Strong, useId, useToastController, Toast, ToastBody, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, RendererProvider, createDOMRenderer, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, treeItemLevelToken, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, MenuItemCheckbox, Switch as Switch$1, SpinButton as SpinButton$1, Input, Dropdown as Dropdown$1, Option, Popover as Popover$1, PopoverTrigger, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch, PresenceBadge, Slider, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, Badge, Label, MessageBarTitle, Subtitle2, useComboboxFilter, Combobox, Textarea as Textarea$1, ToolbarButton, ToolbarDivider, Field } from '@fluentui/react-components';
4
+ import { ErrorCircleRegular, EyeFilled, EyeOffRegular, CheckmarkFilled, EditRegular, FilterRegular, PinFilled, PinRegular, ArrowCircleUpRegular, ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, CopyRegular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, DocumentTextRegular, createFluentIcon, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, SettingsRegular, ArrowUploadRegular, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, WeatherSunnyRegular, WeatherMoonRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, AddRegular, DeleteRegular, FullScreenMaximizeRegular, ChevronDownRegular, ChevronRightRegular, CircleSmallFilled, SaveRegular, PreviousRegular, ArrowPreviousRegular, TriangleLeftRegular, RecordStopRegular, PlayRegular, ArrowNextRegular, NextRegular, PauseRegular, LinkDismissRegular, LinkEditRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, EyeRegular, CloudArrowUpRegular, CloudArrowDownRegular, EyeOffFilled, ArrowMoveFilled, StopFilled, PlayFilled, LockOpenRegular, LockClosedRegular, ResizeRegular, ChevronUpRegular, ArrowResetRegular, CircleHalfFillRegular, EyedropperRegular, PaintBucketRegular, InkStrokeRegular, StackRegular, FilmstripRegular, PauseFilled, WeatherSunnyLowFilled, LayerRegular, FrameRegular, AppGenericRegular, RectangleLandscapeRegular, BorderOutsideRegular, BorderNoneRegular, MyLocationRegular, CameraRegular, LightbulbRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, SoundWaveCircleRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, PersonFeedbackRegular, BranchRegular, DeleteFilled } from '@fluentui/react-icons';
5
5
  import { Color3, Color4 } from '@babylonjs/core/Maths/math.color.js';
6
6
  import { Vector3, Quaternion, Matrix, Vector2, Vector4, TmpVectors } from '@babylonjs/core/Maths/math.vector.js';
7
7
  import { Observable } from '@babylonjs/core/Misc/observable.js';
8
8
  import { GetClassName } from '@babylonjs/core/Misc/typeStore.js';
9
+ import { DataStorage } from '@babylonjs/core/Misc/dataStorage.js';
10
+ import { Logger } from '@babylonjs/core/Misc/logger.js';
9
11
  import { Collapse as Collapse$1, Fade } from '@fluentui/react-motion-components-preview';
10
12
  import { useLocalStorage, useTernaryDarkMode } from 'usehooks-ts';
11
13
  import { AsyncLock } from '@babylonjs/core/Misc/asyncLock.js';
12
14
  import { Deferred } from '@babylonjs/core/Misc/deferred.js';
13
- import { Logger } from '@babylonjs/core/Misc/logger.js';
14
15
  import { Clamp } from '@babylonjs/core/Maths/math.scalar.functions.js';
15
16
  import { VirtualizerScrollView } from '@fluentui-contrib/react-virtualizer';
16
17
  import { UniqueIdGenerator } from '@babylonjs/core/Misc/uniqueIdGenerator.js';
@@ -24,7 +25,6 @@ import { CreateGround } from '@babylonjs/core/Meshes/Builders/groundBuilder.js';
24
25
  import { Tools } from '@babylonjs/core/Misc/tools.js';
25
26
  import { UtilityLayerRenderer } from '@babylonjs/core/Rendering/utilityLayerRenderer.js';
26
27
  import { GridMaterial } from '@babylonjs/materials/grid/gridMaterial.js';
27
- import { DataStorage } from '@babylonjs/core/Misc/dataStorage.js';
28
28
  import { EngineInstrumentation } from '@babylonjs/core/Instrumentation/engineInstrumentation.js';
29
29
  import { SceneInstrumentation } from '@babylonjs/core/Instrumentation/sceneInstrumentation.js';
30
30
  import '@babylonjs/core/Engines/AbstractEngine/abstractEngine.timeQuery.js';
@@ -1018,6 +1018,485 @@ function PropertyImpl(props, ref) {
1018
1018
  */
1019
1019
  const Property = CreateGenericForwardRef(PropertyImpl);
1020
1020
 
1021
+ // ============================================================================
1022
+ // Storage Helpers
1023
+ // ============================================================================
1024
+ const STORAGE_KEY_ROOT = "Babylon/Accordion";
1025
+ const ReadFromStorage = (path, initial) => {
1026
+ try {
1027
+ const stored = DataStorage.ReadString(`${STORAGE_KEY_ROOT}/${path}`, "");
1028
+ return stored ? JSON.parse(stored) : initial;
1029
+ }
1030
+ catch {
1031
+ return initial;
1032
+ }
1033
+ };
1034
+ const WriteToStorage = (path, data) => {
1035
+ DataStorage.WriteString(`${STORAGE_KEY_ROOT}/${path}`, JSON.stringify(data));
1036
+ };
1037
+ // ============================================================================
1038
+ // Reducer
1039
+ // ============================================================================
1040
+ const AccordionReducer = (state, action) => {
1041
+ switch (action.type) {
1042
+ case "SET_SEARCH_TERM":
1043
+ return { ...state, searchTerm: action.term };
1044
+ case "SET_EDIT_MODE":
1045
+ return { ...state, editMode: action.enabled };
1046
+ case "TOGGLE_PINNED": {
1047
+ const isPinned = state.pinnedIds.includes(action.itemId);
1048
+ return {
1049
+ ...state,
1050
+ pinnedIds: isPinned ? state.pinnedIds.filter((id) => id !== action.itemId) : [...state.pinnedIds, action.itemId],
1051
+ };
1052
+ }
1053
+ case "TOGGLE_HIDDEN": {
1054
+ const isHidden = state.hiddenIds.includes(action.itemId);
1055
+ return {
1056
+ ...state,
1057
+ hiddenIds: isHidden ? state.hiddenIds.filter((id) => id !== action.itemId) : [...state.hiddenIds, action.itemId],
1058
+ };
1059
+ }
1060
+ case "MOVE_PINNED_UP": {
1061
+ const index = state.pinnedIds.indexOf(action.itemId);
1062
+ if (index <= 0) {
1063
+ return state;
1064
+ }
1065
+ const newPinnedIds = [...state.pinnedIds];
1066
+ [newPinnedIds[index - 1], newPinnedIds[index]] = [newPinnedIds[index], newPinnedIds[index - 1]];
1067
+ return { ...state, pinnedIds: newPinnedIds };
1068
+ }
1069
+ case "SHOW_ALL":
1070
+ return { ...state, hiddenIds: [] };
1071
+ case "HIDE_ALL_VISIBLE":
1072
+ return {
1073
+ ...state,
1074
+ hiddenIds: [...new Set([...state.hiddenIds, ...action.visibleItemIds])],
1075
+ };
1076
+ default:
1077
+ return state;
1078
+ }
1079
+ };
1080
+ const AccordionContext = createContext(undefined);
1081
+ /**
1082
+ * Hook to create and manage the AccordionContext value.
1083
+ *
1084
+ * @param props - AccordionProps
1085
+ * @returns AccordionContextValue, or undefined if no features are enabled or no uniqueId is provided.
1086
+ */
1087
+ function useAccordionContext(props) {
1088
+ const { uniqueId: accordionId, enablePinnedItems, enableHiddenItems, enableSearchItems } = props;
1089
+ const features = useMemo(() => ({
1090
+ pinning: enablePinnedItems ?? false,
1091
+ hiding: enableHiddenItems ?? false,
1092
+ search: enableSearchItems ?? false,
1093
+ }), [enablePinnedItems, enableHiddenItems, enableSearchItems]);
1094
+ const hasFeatures = features.pinning || features.hiding || features.search;
1095
+ // Initialize state from localStorage
1096
+ const initialState = useMemo(() => {
1097
+ if (!accordionId || !hasFeatures) {
1098
+ return { pinnedIds: [], hiddenIds: [], searchTerm: "", editMode: false };
1099
+ }
1100
+ return {
1101
+ pinnedIds: features.pinning ? ReadFromStorage(`Pinned/${accordionId}`, []) : [],
1102
+ hiddenIds: features.hiding ? ReadFromStorage(`Hidden/${accordionId}`, []) : [],
1103
+ searchTerm: "",
1104
+ editMode: false,
1105
+ };
1106
+ }, [accordionId, hasFeatures, features.pinning, features.hiding]);
1107
+ const [state, dispatch] = useReducer(AccordionReducer, initialState);
1108
+ const pinnedContainerRef = useRef(null);
1109
+ const registeredItemIds = useRef(new Set());
1110
+ // Persist pinnedIds to localStorage when they change
1111
+ useEffect(() => {
1112
+ if (accordionId && features.pinning) {
1113
+ WriteToStorage(`Pinned/${accordionId}`, state.pinnedIds);
1114
+ }
1115
+ }, [accordionId, features.pinning, state.pinnedIds]);
1116
+ // Persist hiddenIds to localStorage when they change
1117
+ useEffect(() => {
1118
+ if (accordionId && features.hiding) {
1119
+ WriteToStorage(`Hidden/${accordionId}`, state.hiddenIds);
1120
+ }
1121
+ }, [accordionId, features.hiding, state.hiddenIds]);
1122
+ // Return undefined if no accordionId or no features enabled
1123
+ if (!accordionId || !hasFeatures) {
1124
+ return undefined;
1125
+ }
1126
+ return {
1127
+ accordionId,
1128
+ state,
1129
+ dispatch,
1130
+ features,
1131
+ pinnedContainerRef,
1132
+ registeredItemIds,
1133
+ };
1134
+ }
1135
+ const AccordionSectionBlockContext = createContext(undefined);
1136
+ /**
1137
+ * Hook to create the AccordionSectionBlockContext value.
1138
+ *
1139
+ * @param props - AccordionSectionBlockProps
1140
+ * @returns AccordionSectionBlockContextValue
1141
+ */
1142
+ function useAccordionSectionBlockContext(props) {
1143
+ const { sectionId } = props;
1144
+ return useMemo(() => ({ sectionId }), [sectionId]);
1145
+ }
1146
+ // ============================================================================
1147
+ // Item Depth Context (to detect nested AccordionSectionItems)
1148
+ // ============================================================================
1149
+ /**
1150
+ * Context to track whether we're inside an AccordionSectionItem.
1151
+ * Used to prevent nested items from being individually manageable.
1152
+ */
1153
+ const AccordionItemDepthContext = createContext(false);
1154
+ /**
1155
+ * Hook to compute item state from accordion context.
1156
+ *
1157
+ * @param props - AccordionSectionItemProps
1158
+ * @returns AccordionItemState, or undefined if no accordion context or nested item.
1159
+ */
1160
+ function useAccordionSectionItemState(props) {
1161
+ const { uniqueId: itemId, label: itemLabel, staticItem } = props;
1162
+ const accordionCtx = useContext(AccordionContext);
1163
+ const sectionCtx = useContext(AccordionSectionBlockContext);
1164
+ const isNested = useContext(AccordionItemDepthContext);
1165
+ // Build the globally unique item ID
1166
+ const itemUniqueId = useMemo(() => {
1167
+ if (!accordionCtx || !sectionCtx) {
1168
+ return "";
1169
+ }
1170
+ return `${accordionCtx.accordionId}\0${sectionCtx.sectionId}\0${itemId}`;
1171
+ }, [accordionCtx?.accordionId, sectionCtx?.sectionId, itemId]);
1172
+ // Debug: warn if itemId changes (should be stable)
1173
+ const prevItemIdRef = useRef(itemId);
1174
+ useEffect(() => {
1175
+ if (prevItemIdRef.current !== itemId) {
1176
+ Logger.Warn(`Accordion: The uniqueId "${itemId}" in section "${sectionCtx?.sectionId}" has changed from "${prevItemIdRef.current}". ` +
1177
+ `Each item must have a unique, stable ID for pin/hide persistence to work correctly.`);
1178
+ }
1179
+ prevItemIdRef.current = itemId;
1180
+ }, [itemId, sectionCtx?.sectionId]);
1181
+ // Debug: warn if itemUniqueId is not unique (duplicate detection)
1182
+ useEffect(() => {
1183
+ if (!accordionCtx || !itemUniqueId) {
1184
+ return;
1185
+ }
1186
+ const { registeredItemIds } = accordionCtx;
1187
+ if (registeredItemIds.current.has(itemUniqueId)) {
1188
+ Logger.Warn(`Accordion: Duplicate uniqueId "${itemId}" detected in section "${sectionCtx?.sectionId}". ` +
1189
+ `Each item must have a unique ID within its section for pin/hide persistence to work correctly.`);
1190
+ }
1191
+ else {
1192
+ registeredItemIds.current.add(itemUniqueId);
1193
+ }
1194
+ return () => {
1195
+ registeredItemIds.current.delete(itemUniqueId);
1196
+ };
1197
+ }, [accordionCtx, itemUniqueId, itemId, sectionCtx?.sectionId]);
1198
+ // If no context, static item, or nested, return undefined
1199
+ if (!accordionCtx || staticItem) {
1200
+ return undefined;
1201
+ }
1202
+ const { state, dispatch, features } = accordionCtx;
1203
+ const { pinnedIds, hiddenIds, searchTerm, editMode } = state;
1204
+ // Compute derived state
1205
+ const isPinned = features.pinning && pinnedIds.includes(itemUniqueId);
1206
+ const isHidden = features.hiding && hiddenIds.includes(itemUniqueId);
1207
+ const pinnedIndex = isPinned ? pinnedIds.indexOf(itemUniqueId) : -1;
1208
+ // Search matching
1209
+ const searchText = (itemLabel ?? itemId).toLowerCase();
1210
+ const isMatch = !features.search || !searchTerm || searchText.includes(searchTerm.toLowerCase());
1211
+ return {
1212
+ itemUniqueId,
1213
+ isNested,
1214
+ isPinned,
1215
+ isHidden,
1216
+ isMatch,
1217
+ pinnedIndex,
1218
+ inEditMode: editMode,
1219
+ actions: {
1220
+ togglePinned: () => dispatch({ type: "TOGGLE_PINNED", itemId: itemUniqueId }),
1221
+ toggleHidden: () => dispatch({ type: "TOGGLE_HIDDEN", itemId: itemUniqueId }),
1222
+ movePinnedUp: () => dispatch({ type: "MOVE_PINNED_UP", itemId: itemUniqueId }),
1223
+ },
1224
+ };
1225
+ }
1226
+
1227
+ const useStyles$S = makeStyles({
1228
+ accordion: {
1229
+ display: "flex",
1230
+ flexDirection: "column",
1231
+ height: "100%",
1232
+ },
1233
+ accordionBody: {
1234
+ overflowX: "hidden",
1235
+ overflowY: "auto",
1236
+ paddingBottom: tokens.spacingVerticalM, // bottom padding since there is no divider at the bottom
1237
+ },
1238
+ divider: {
1239
+ paddingTop: CustomTokens.dividerGap,
1240
+ paddingBottom: CustomTokens.dividerGap,
1241
+ },
1242
+ dividerSmall: {
1243
+ paddingTop: CustomTokens.dividerGapSmall,
1244
+ paddingBottom: CustomTokens.dividerGapSmall,
1245
+ },
1246
+ panelDiv: {
1247
+ display: "flex",
1248
+ flexDirection: "column",
1249
+ overflow: "hidden",
1250
+ },
1251
+ highlightDiv: {
1252
+ borderRadius: tokens.borderRadiusLarge,
1253
+ animationDuration: "1s",
1254
+ animationTimingFunction: "ease-in-out",
1255
+ animationIterationCount: "5",
1256
+ animationFillMode: "forwards",
1257
+ animationName: {
1258
+ from: {
1259
+ boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,
1260
+ },
1261
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1262
+ "50%": {
1263
+ boxShadow: `inset 0 0 12px ${tokens.colorBrandBackground}`,
1264
+ },
1265
+ to: {
1266
+ boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,
1267
+ },
1268
+ },
1269
+ },
1270
+ menuBar: {
1271
+ display: "flex",
1272
+ },
1273
+ menuBarControls: {
1274
+ display: "flex",
1275
+ flexGrow: 1,
1276
+ justifyContent: "end",
1277
+ },
1278
+ sectionEmpty: {
1279
+ display: "none",
1280
+ },
1281
+ sectionItemContainer: {
1282
+ display: "flex",
1283
+ flexDirection: "row",
1284
+ },
1285
+ sectionItemButtons: {
1286
+ display: "flex",
1287
+ flexDirection: "row",
1288
+ alignItems: "start",
1289
+ marginRight: tokens.spacingHorizontalXS,
1290
+ },
1291
+ pinnedContainer: {
1292
+ display: "flex",
1293
+ flexDirection: "column",
1294
+ },
1295
+ pinnedContainerEmpty: {
1296
+ "&:not(:only-child)": {
1297
+ display: "none",
1298
+ },
1299
+ },
1300
+ searchBox: {
1301
+ width: "100%",
1302
+ },
1303
+ });
1304
+ /**
1305
+ * Renders the menu bar and control buttons.
1306
+ *
1307
+ * @returns `div`, or `undefined` if all features are disabled.
1308
+ */
1309
+ const AccordionMenuBar = () => {
1310
+ AccordionMenuBar.displayName = "AccordionMenuBar";
1311
+ const classes = useStyles$S();
1312
+ const accordionCtx = useContext(AccordionContext);
1313
+ if (!accordionCtx) {
1314
+ return null;
1315
+ }
1316
+ const { state, dispatch, features } = accordionCtx;
1317
+ const { editMode } = state;
1318
+ return (jsxs("div", { className: classes.menuBar, children: [jsx(AccordionSearchBox, {}), jsxs("div", { className: classes.menuBarControls, children: [features.hiding && editMode && (jsxs(Fragment, { children: [jsx(Button, { title: "Show all", icon: EyeFilled, appearance: "subtle", onClick: () => dispatch({ type: "SHOW_ALL" }) }), jsx(Button, { title: "Hide all", icon: EyeOffRegular, appearance: "subtle", onClick: () => {
1319
+ // Hide all visible items - we pass all non-hidden, matching items
1320
+ // For simplicity, we dispatch with an empty array; the actual filtering
1321
+ // would need to be done with knowledge of all registered items.
1322
+ // This is a limitation - in a full implementation, you'd track registered items.
1323
+ dispatch({ type: "HIDE_ALL_VISIBLE", visibleItemIds: [] });
1324
+ } })] })), (features.pinning || features.hiding) && (jsx(Button, { title: "Edit mode", icon: editMode ? CheckmarkFilled : EditRegular, appearance: editMode ? "primary" : "subtle", onClick: () => dispatch({ type: "SET_EDIT_MODE", enabled: !editMode }) }))] })] }));
1325
+ };
1326
+ /**
1327
+ * Wrapper component that must encapsulate the section headers and panels.
1328
+ * - Stores the section ID for use in `AccordionSectionItem`.
1329
+ *
1330
+ * @param props - `AccordionSectionBlockProps`
1331
+ * @returns `AccordionSectionBlockContext.Provider`, or `AccordionItem` if all features are disabled.
1332
+ */
1333
+ const AccordionSectionBlock = (props) => {
1334
+ AccordionSectionBlock.displayName = "AccordionSectionBlock";
1335
+ const { children, sectionId } = props;
1336
+ const accordionCtx = useContext(AccordionContext);
1337
+ const sectionContext = useAccordionSectionBlockContext(props);
1338
+ if (accordionCtx) {
1339
+ return (jsx(AccordionSectionBlockContext.Provider, { value: sectionContext, children: jsx(AccordionItem, { value: sectionId, children: children }) }));
1340
+ }
1341
+ return jsx(AccordionItem, { value: sectionId, children: children });
1342
+ };
1343
+ /**
1344
+ * Wrapper component that must encapsulate individual items.
1345
+ * - Renders the pin button and tracks the pinned state of the item.
1346
+ * - Renders the hide button and tracks the hidden state of the item.
1347
+ * - Filters items based on the current search term.
1348
+ *
1349
+ * @param props - `AccordionSectionItemProps`
1350
+ * @returns `Portal` if pinned; `null` if hidden/filtered; `children` otherwise.
1351
+ */
1352
+ const AccordionSectionItem = (props) => {
1353
+ AccordionSectionItem.displayName = "AccordionSectionItem";
1354
+ const { children, staticItem } = props;
1355
+ const classes = useStyles$S();
1356
+ const accordionCtx = useContext(AccordionContext);
1357
+ const itemState = useAccordionSectionItemState(props);
1358
+ const [ctrlMode, setCtrlMode] = useState(false);
1359
+ // If static item or no context, just render children
1360
+ if (staticItem || !accordionCtx || !itemState) {
1361
+ return jsx(Fragment, { children: children });
1362
+ }
1363
+ const { pinnedContainerRef, features } = accordionCtx;
1364
+ const { isNested, isPinned, isHidden, isMatch, pinnedIndex, inEditMode, actions } = itemState;
1365
+ // Nested items just render children (don't show controls)
1366
+ if (isNested) {
1367
+ return jsx(Fragment, { children: children });
1368
+ }
1369
+ // If hidden (and not in edit mode) or doesn't match search, don't render
1370
+ if ((isHidden && !inEditMode) || !isMatch) {
1371
+ return null;
1372
+ }
1373
+ const pinnedContainer = isPinned ? pinnedContainerRef.current : null;
1374
+ const showControls = inEditMode || ctrlMode;
1375
+ const onMouseMove = (e) => {
1376
+ if (e.ctrlKey !== ctrlMode) {
1377
+ setCtrlMode(e.ctrlKey);
1378
+ }
1379
+ };
1380
+ const onMouseLeave = () => {
1381
+ if (ctrlMode) {
1382
+ setCtrlMode(false);
1383
+ }
1384
+ };
1385
+ const itemElement = (jsxs("div", { className: classes.sectionItemContainer, style: isPinned ? { order: pinnedIndex } : undefined, onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, children: [showControls && (jsxs("div", { className: classes.sectionItemButtons, children: [features.hiding && (jsx(Button, { title: isHidden ? "Unhide" : "Hide", icon: isHidden ? EyeOffRegular : EyeFilled, appearance: "transparent", onClick: actions.toggleHidden })), features.pinning && (jsxs(Fragment, { children: [jsx(Button, { title: isPinned ? "Unpin" : "Pin", icon: isPinned ? PinFilled : PinRegular, appearance: "transparent", onClick: actions.togglePinned }), isPinned && (jsx(Button, { title: "Move up", icon: ArrowCircleUpRegular, appearance: "transparent", disabled: pinnedIndex === 0, onClick: actions.movePinnedUp }))] }))] })), jsx(AccordionItemDepthContext.Provider, { value: true, children: children })] }));
1386
+ return pinnedContainer ? jsx(Portal, { mountNode: pinnedContainer, children: itemElement }) : itemElement;
1387
+ };
1388
+ /**
1389
+ * Renders the Pinned section container and defines the portal target for the pinned items.
1390
+ *
1391
+ * @returns `div`
1392
+ */
1393
+ const AccordionPinnedContainer = () => {
1394
+ AccordionPinnedContainer.displayName = "AccordionPinnedContainer";
1395
+ const classes = useStyles$S();
1396
+ const accordionCtx = useContext(AccordionContext);
1397
+ return (jsx("div", { ref: accordionCtx?.pinnedContainerRef, className: classes.pinnedContainer, children: jsx(MessageBar$1, { className: classes.pinnedContainerEmpty, children: jsx(MessageBarBody, { children: "No pinned items" }) }) }));
1398
+ };
1399
+ /**
1400
+ * Renders the search box for filtering items.
1401
+ *
1402
+ * @returns `SearchBox`, or `null` if the feature is disabled.
1403
+ */
1404
+ const AccordionSearchBox = () => {
1405
+ AccordionSearchBox.displayName = "AccordionSearchBox";
1406
+ const classes = useStyles$S();
1407
+ const accordionCtx = useContext(AccordionContext);
1408
+ if (!accordionCtx?.features.search) {
1409
+ return null;
1410
+ }
1411
+ const { state, dispatch } = accordionCtx;
1412
+ return (jsx(SearchBox$1, { className: classes.searchBox, appearance: "underline", contentBefore: jsx(FilterRegular, {}), placeholder: "Filter", value: state.searchTerm, onChange: (_, data) => dispatch({ type: "SET_SEARCH_TERM", term: data.value }) }));
1413
+ };
1414
+ /**
1415
+ * Wrapper component that must encapsulate the section body.
1416
+ *
1417
+ * @param props - `AccordionSectionProps`
1418
+ * @returns `div`
1419
+ */
1420
+ const AccordionSection = (props) => {
1421
+ AccordionSection.displayName = "AccordionSection";
1422
+ const classes = useStyles$S();
1423
+ return jsx("div", { className: classes.panelDiv, children: props.children });
1424
+ };
1425
+ const StringAccordion = Accordion$1;
1426
+ const Accordion = forwardRef((props, ref) => {
1427
+ Accordion.displayName = "Accordion";
1428
+ const { children, highlightSections, ...rest } = props;
1429
+ const classes = useStyles$S();
1430
+ const { size } = useContext(ToolContext);
1431
+ const accordionCtx = useAccordionContext(props);
1432
+ const hasPinning = accordionCtx?.features.pinning ?? false;
1433
+ const pinnedSectionElement = useMemo(() => {
1434
+ return (hasPinning && (jsx(AccordionSection, { title: "Pinned", collapseByDefault: false, children: jsx(AccordionPinnedContainer, {}) })));
1435
+ }, [hasPinning]);
1436
+ // Prevents sections contents from unmounting when closed, allowing their elements to be used in the Pinned section.
1437
+ const preventUnmountMotion = useMemo(() => {
1438
+ // https://github.com/microsoft/fluentui/issues/34309#issuecomment-2824364945
1439
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1440
+ return hasPinning ? { children: (Component, props) => jsx(Component, { ...props, unmountOnExit: false }) } : undefined;
1441
+ }, [hasPinning]);
1442
+ const validChildren = useMemo(() => {
1443
+ return (Children.map([pinnedSectionElement, children], (child) => {
1444
+ if (isValidElement(child)) {
1445
+ const childProps = child.props;
1446
+ if (childProps.title) {
1447
+ return {
1448
+ title: childProps.title,
1449
+ collapseByDefault: childProps.collapseByDefault,
1450
+ content: child,
1451
+ };
1452
+ }
1453
+ }
1454
+ return null;
1455
+ })?.filter(Boolean) ?? []);
1456
+ }, [children]);
1457
+ // Tracks open items, and used to tell the Accordion which sections should be expanded.
1458
+ const [openItems, setOpenItems] = useState(validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title));
1459
+ // Tracks closed items, which is needed so that when the children change, we only update the open/closed state
1460
+ // (depending on the collapseByDefault prop) for items that have not been explicitly opened or closed.
1461
+ const [closedItems, setClosedItems] = useState(validChildren.filter((child) => child.collapseByDefault).map((child) => child.title));
1462
+ const internalOpenItemsRef = useRef(openItems);
1463
+ // When highlight sections is requested, we temporarily override the open items, but if highlight sections is cleared,
1464
+ // then we revert back to the normal open items tracking.
1465
+ useLayoutEffect(() => {
1466
+ if (highlightSections) {
1467
+ internalOpenItemsRef.current = [...openItems];
1468
+ setOpenItems([...highlightSections]);
1469
+ }
1470
+ else {
1471
+ setOpenItems([...(internalOpenItemsRef.current ?? [])]);
1472
+ internalOpenItemsRef.current = undefined;
1473
+ }
1474
+ }, [highlightSections]);
1475
+ useEffect(() => {
1476
+ for (const defaultOpenItem of validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title)) {
1477
+ // If a child is not marked as collapseByDefault, then it should be opened by default, and
1478
+ // it is only "default" if it hasn't already been explicitly added to the opened or closed list.
1479
+ if (!closedItems.includes(defaultOpenItem) && !openItems.includes(defaultOpenItem)) {
1480
+ setOpenItems((prev) => [...prev, defaultOpenItem]);
1481
+ }
1482
+ }
1483
+ }, [validChildren]);
1484
+ const onToggle = useCallback((event, data) => {
1485
+ if (data.openItems.includes(data.value)) {
1486
+ setOpenItems((prev) => [...prev, data.value]);
1487
+ setClosedItems((prev) => prev.filter((item) => item !== data.value));
1488
+ }
1489
+ else {
1490
+ setClosedItems((prev) => [...prev, data.value]);
1491
+ setOpenItems((prev) => prev.filter((item) => item !== data.value));
1492
+ }
1493
+ }, []);
1494
+ return (jsx(StringAccordion, { ref: ref, className: classes.accordion, collapsible: true, multiple: true, onToggle: onToggle, openItems: openItems, ...rest, children: jsxs(AccordionContext.Provider, { value: accordionCtx, children: [jsx(AccordionMenuBar, {}), jsx("div", { className: classes.accordionBody, children: validChildren.map((child, index) => {
1495
+ const isHighlighted = highlightSections?.includes(child.title);
1496
+ return (jsxs(AccordionSectionBlock, { sectionId: child.title, children: [jsxs("div", { className: isHighlighted ? classes.highlightDiv : undefined, children: [jsx(AccordionHeader, { size: size, children: jsx(Subtitle2Stronger, { children: child.title }) }), jsx(AccordionPanel, { collapseMotion: preventUnmountMotion, children: jsx("div", { className: classes.panelDiv, children: child.content }) })] }), index < validChildren.length - 1 && jsx(Divider, { inset: true, className: size === "small" ? classes.dividerSmall : classes.divider })] }, child.content.key ?? child.title));
1497
+ }) })] }) }));
1498
+ });
1499
+
1021
1500
  const useCollapseStyles = makeStyles({
1022
1501
  collapseContent: {
1023
1502
  overflow: "hidden",
@@ -1039,7 +1518,9 @@ const useCollapseStyles = makeStyles({
1039
1518
  const Collapse = (props) => {
1040
1519
  Collapse.displayName = "Collapse";
1041
1520
  const classes = useCollapseStyles();
1042
- return (jsx(Collapse$1, { visible: props.visible, orientation: props.orientation, children: jsx("div", { className: `${classes.collapseContent} ${props.orientation === "horizontal" ? classes.horizontal : classes.vertical}`, children: props.children }) }));
1521
+ // Since portalling breaks DOM hierarchy, `unmountOnExit` is required to ensure descendants are unmounted when the logical ancestor collapses.
1522
+ // If this is a breaking change, the alternative would be creating a context to pass the `visible` state down to the descendants.
1523
+ return (jsx(Collapse$1, { visible: props.visible, orientation: props.orientation, unmountOnExit: true, children: jsx("div", { className: `${classes.collapseContent} ${props.orientation === "horizontal" ? classes.horizontal : classes.vertical}`, children: props.children }) }));
1043
1524
  };
1044
1525
 
1045
1526
  const Link = forwardRef((props, ref) => {
@@ -1050,7 +1531,7 @@ const Link = forwardRef((props, ref) => {
1050
1531
  });
1051
1532
  Link.displayName = "Link";
1052
1533
 
1053
- const useStyles$S = makeStyles({
1534
+ const useStyles$R = makeStyles({
1054
1535
  button: {
1055
1536
  display: "flex",
1056
1537
  alignItems: "center",
@@ -1068,7 +1549,7 @@ const ToggleButton = (props) => {
1068
1549
  ToggleButton.displayName = "ToggleButton";
1069
1550
  const { value, onChange, title, appearance = "subtle" } = props;
1070
1551
  const { size } = useContext(ToolContext);
1071
- const classes = useStyles$S();
1552
+ const classes = useStyles$R();
1072
1553
  const [checked, setChecked] = useState(value);
1073
1554
  const toggle = useCallback(() => {
1074
1555
  setChecked((prev) => {
@@ -1098,7 +1579,7 @@ const useInfoLabelStyles = makeStyles({
1098
1579
  textOverflow: "ellipsis",
1099
1580
  },
1100
1581
  copyable: {
1101
- cursor: "copy",
1582
+ cursor: "pointer",
1102
1583
  },
1103
1584
  });
1104
1585
  /**
@@ -1224,7 +1705,7 @@ const PropertyLine = forwardRef((props, ref) => {
1224
1705
  PropertyLine.displayName = "PropertyLine";
1225
1706
  const { disableCopy, size } = useContext(ToolContext);
1226
1707
  const classes = usePropertyLineStyles();
1227
- const { label, onCopy, expandedContent, children, nullable, ignoreNullable } = props;
1708
+ const { label, uniqueId, onCopy, expandedContent, children, nullable, ignoreNullable } = props;
1228
1709
  const [expanded, setExpanded] = useState("expandByDefault" in props ? props.expandByDefault : false);
1229
1710
  const cachedVal = useRef(nullable ? props.value : null);
1230
1711
  const { showToast } = useToast();
@@ -1248,7 +1729,7 @@ const PropertyLine = forwardRef((props, ref) => {
1248
1729
  defaultValue: undefined, // Don't pass defaultValue to children as there is no guarantee how this will be used and we can't mix controlled + uncontrolled state
1249
1730
  })
1250
1731
  : children;
1251
- return (jsxs(LineContainer, { ref: ref, children: [jsxs("div", { className: classes.baseLine, children: [jsx(InfoLabel, { className: classes.infoLabel, htmlFor: "property", info: description, label: label, flexLabel: true, onContextMenu: onCopy ? handleContextMenu : undefined }), jsxs("div", { className: classes.rightContent, id: "property", children: [expandedContent && (jsx(ToggleButton, { title: "Expand/Collapse property", appearance: "transparent", checkedIcon: size === "small" ? ChevronCircleDown16Regular : ChevronCircleDown20Regular, uncheckedIcon: size === "small" ? ChevronCircleRight16Regular : ChevronCircleRight20Regular, value: expanded === true, onChange: setExpanded })), nullable && !ignoreNullable && (
1732
+ return (jsxs(LineContainer, { ref: ref, uniqueId: uniqueId ?? label, label: label, children: [jsxs("div", { className: classes.baseLine, children: [jsx(InfoLabel, { className: classes.infoLabel, htmlFor: "property", info: description, label: label, flexLabel: true, onContextMenu: onCopy ? handleContextMenu : undefined }), jsxs("div", { className: classes.rightContent, id: "property", children: [expandedContent && (jsx(ToggleButton, { title: "Expand/Collapse property", appearance: "transparent", checkedIcon: size === "small" ? ChevronCircleDown16Regular : ChevronCircleDown20Regular, uncheckedIcon: size === "small" ? ChevronCircleRight16Regular : ChevronCircleRight20Regular, value: expanded === true, onChange: setExpanded })), nullable && !ignoreNullable && (
1252
1733
  // If this is a nullableProperty and ignoreNullable was not sent, display a checkbox used to toggle null ('checked' means 'non null')
1253
1734
  jsx(Tooltip, { content: props.value == null ? "Enable property" : "Disable property (set to null)", children: jsx(Checkbox$1, { className: classes.checkbox, indicator: { className: classes.checkboxIndicator }, checked: !(props.value == null), onChange: (_, data) => {
1254
1735
  if (data.checked) {
@@ -1285,8 +1766,9 @@ const useLineStyles = makeStyles({
1285
1766
  });
1286
1767
  const LineContainer = forwardRef((props, ref) => {
1287
1768
  const { size } = useContext(ToolContext);
1769
+ const { children, uniqueId, label, ...rest } = props;
1288
1770
  const classes = useLineStyles();
1289
- return (jsx("div", { ref: ref, className: mergeClasses(classes.container, size == "small" ? classes.containerSmall : undefined), ...props, children: props.children }));
1771
+ return (jsx(AccordionSectionItem, { uniqueId: uniqueId, label: label, children: jsx("div", { ref: ref, className: mergeClasses(classes.container, size == "small" ? classes.containerSmall : undefined), ...rest, children: children }) }));
1290
1772
  });
1291
1773
  const PlaceholderPropertyLine = (props) => {
1292
1774
  return (jsx(PropertyLine, { ...props, children: jsx(Body1, { children: props.value }) }));
@@ -1317,117 +1799,6 @@ const LinkToEntityPropertyLine = (props) => {
1317
1799
  !linkedEntity.reservedDataStore?.hidden && jsx(LinkPropertyLine, { ...rest, value: linkedEntity.name, onLink: () => (selectionService.selectedEntity = linkedEntity) }));
1318
1800
  };
1319
1801
 
1320
- const useStyles$R = makeStyles({
1321
- accordion: {
1322
- overflowX: "hidden",
1323
- overflowY: "auto",
1324
- paddingBottom: tokens.spacingVerticalM, // bottom padding since there is no divider at the bottom
1325
- display: "flex",
1326
- flexDirection: "column",
1327
- height: "100%",
1328
- },
1329
- divider: {
1330
- paddingTop: CustomTokens.dividerGap,
1331
- paddingBottom: CustomTokens.dividerGap,
1332
- },
1333
- dividerSmall: {
1334
- paddingTop: CustomTokens.dividerGapSmall,
1335
- paddingBottom: CustomTokens.dividerGapSmall,
1336
- },
1337
- panelDiv: {
1338
- display: "flex",
1339
- flexDirection: "column",
1340
- overflow: "hidden",
1341
- },
1342
- highlightDiv: {
1343
- borderRadius: tokens.borderRadiusLarge,
1344
- animationDuration: "1s",
1345
- animationTimingFunction: "ease-in-out",
1346
- animationIterationCount: "5",
1347
- animationFillMode: "forwards",
1348
- animationName: {
1349
- from: {
1350
- boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,
1351
- },
1352
- // eslint-disable-next-line @typescript-eslint/naming-convention
1353
- "50%": {
1354
- boxShadow: `inset 0 0 12px ${tokens.colorBrandBackground}`,
1355
- },
1356
- to: {
1357
- boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,
1358
- },
1359
- },
1360
- },
1361
- });
1362
- const AccordionSection = (props) => {
1363
- AccordionSection.displayName = "AccordionSection";
1364
- const classes = useStyles$R();
1365
- return jsx("div", { className: classes.panelDiv, children: props.children });
1366
- };
1367
- const StringAccordion = Accordion$1;
1368
- const Accordion = forwardRef((props, ref) => {
1369
- Accordion.displayName = "Accordion";
1370
- const classes = useStyles$R();
1371
- const { size } = useContext(ToolContext);
1372
- const { children, highlightSections, ...rest } = props;
1373
- const validChildren = useMemo(() => {
1374
- return (Children.map(children, (child) => {
1375
- if (isValidElement(child)) {
1376
- const childProps = child.props;
1377
- if (childProps.title) {
1378
- return {
1379
- title: childProps.title,
1380
- collapseByDefault: childProps.collapseByDefault,
1381
- content: child,
1382
- };
1383
- }
1384
- }
1385
- return null;
1386
- })?.filter(Boolean) ?? []);
1387
- }, [children]);
1388
- // Tracks open items, and used to tell the Accordion which sections should be expanded.
1389
- const [openItems, setOpenItems] = useState(validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title));
1390
- // Tracks closed items, which is needed so that when the children change, we only update the open/closed state
1391
- // (depending on the collapseByDefault prop) for items that have not been explicitly opened or closed.
1392
- const [closedItems, setClosedItems] = useState(validChildren.filter((child) => child.collapseByDefault).map((child) => child.title));
1393
- const internalOpenItemsRef = useRef(openItems);
1394
- // When highlight sections is requested, we temporarily override the open items, but if highlight sections is cleared,
1395
- // then we revert back to the normal open items tracking.
1396
- useLayoutEffect(() => {
1397
- if (highlightSections) {
1398
- internalOpenItemsRef.current = [...openItems];
1399
- setOpenItems([...highlightSections]);
1400
- }
1401
- else {
1402
- setOpenItems([...(internalOpenItemsRef.current ?? [])]);
1403
- internalOpenItemsRef.current = undefined;
1404
- }
1405
- }, [highlightSections]);
1406
- useEffect(() => {
1407
- for (const defaultOpenItem of validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title)) {
1408
- // If a child is not marked as collapseByDefault, then it should be opened by default, and
1409
- // it is only "default" if it hasn't already been explicitly added to the opened or closed list.
1410
- if (!closedItems.includes(defaultOpenItem) && !openItems.includes(defaultOpenItem)) {
1411
- setOpenItems((prev) => [...prev, defaultOpenItem]);
1412
- }
1413
- }
1414
- }, [validChildren]);
1415
- const onToggle = useCallback((event, data) => {
1416
- if (data.openItems.includes(data.value)) {
1417
- setOpenItems((prev) => [...prev, data.value]);
1418
- setClosedItems((prev) => prev.filter((item) => item !== data.value));
1419
- }
1420
- else {
1421
- setClosedItems((prev) => [...prev, data.value]);
1422
- setOpenItems((prev) => prev.filter((item) => item !== data.value));
1423
- }
1424
- }, []);
1425
- return (jsx(StringAccordion, { ref: ref, className: classes.accordion, collapsible: true, multiple: true, onToggle: onToggle, openItems: openItems, ...rest, children: validChildren.map((child, index) => {
1426
- const isHighlighted = highlightSections?.includes(child.title);
1427
- return (jsxs(AccordionItem, { value: child.title, children: [jsxs("div", { className: isHighlighted ? classes.highlightDiv : undefined, children: [jsx(AccordionHeader, { size: size, children: jsx(Subtitle2Stronger, { children: child.title }) }), jsx(AccordionPanel, { children: jsx("div", { className: classes.panelDiv, children: child.content }) })] }), index < validChildren.length - 1 && jsx(Divider, { inset: true, className: size === "small" ? classes.dividerSmall : classes.divider })] }, child.content.key ?? child.title));
1428
- }) }));
1429
- });
1430
-
1431
1802
  const CompactModeStorageKey = "Babylon/Settings/IsCompactMode";
1432
1803
  const SidePaneDockOverridesStorageKey = "Babylon/Settings/SidePaneDockOverrides";
1433
1804
  const DisableCopyStorageKey = "Babylon/Settings/DisableCopy";
@@ -1517,7 +1888,7 @@ const useStyles$Q = makeStyles({
1517
1888
  });
1518
1889
  function ExtensibleAccordion(props) {
1519
1890
  const classes = useStyles$Q();
1520
- const { children, sections, sectionContent, context, sectionsRef } = props;
1891
+ const { children, sections, sectionContent, context, sectionsRef, ...rest } = props;
1521
1892
  const defaultSections = useMemo(() => {
1522
1893
  const defaultSections = [];
1523
1894
  if (children) {
@@ -1616,7 +1987,7 @@ function ExtensibleAccordion(props) {
1616
1987
  },
1617
1988
  };
1618
1989
  }, []);
1619
- return (jsx("div", { className: classes.rootDiv, children: visibleSections.length > -1 && (jsx(UXContextProvider, { children: jsxs(Accordion, { highlightSections: highlightSections, children: [...visibleSections.map((section) => {
1990
+ return (jsx("div", { className: classes.rootDiv, children: visibleSections.length > -1 && (jsx(UXContextProvider, { children: jsxs(Accordion, { highlightSections: highlightSections, ...rest, children: [...visibleSections.map((section) => {
1620
1991
  return (jsx(AccordionSection, { title: section.identity, collapseByDefault: section.collapseByDefault, children: section.components }, section.identity));
1621
1992
  })] }) })) }));
1622
1993
  }
@@ -2249,16 +2620,17 @@ const useStyles$M = makeStyles({
2249
2620
  bar: {
2250
2621
  display: "flex",
2251
2622
  flex: "1",
2252
- height: "32px",
2253
2623
  overflow: "hidden",
2254
2624
  padding: `${tokens.spacingVerticalXXS} ${tokens.spacingHorizontalXXS}`,
2255
- border: `1px solid ${tokens.colorNeutralStroke2}`,
2256
- borderBottomWidth: 0,
2257
- backgroundColor: tokens.colorNeutralBackground1,
2625
+ borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
2626
+ backgroundColor: tokens.colorNeutralBackground2,
2258
2627
  },
2259
2628
  barTop: {
2260
2629
  borderTopWidth: 0,
2261
2630
  },
2631
+ barBottom: {
2632
+ borderTop: `1px solid ${tokens.colorNeutralStroke2}`,
2633
+ },
2262
2634
  barLeft: {
2263
2635
  marginRight: "auto",
2264
2636
  display: "flex",
@@ -2277,7 +2649,7 @@ const useStyles$M = makeStyles({
2277
2649
  display: "flex",
2278
2650
  },
2279
2651
  paneTabListDiv: {
2280
- backgroundColor: tokens.colorNeutralBackground2,
2652
+ backgroundColor: tokens.colorNeutralBackground1,
2281
2653
  flex: "0 0 auto",
2282
2654
  display: "flex",
2283
2655
  },
@@ -2288,7 +2660,11 @@ const useStyles$M = makeStyles({
2288
2660
  flexDirection: "row",
2289
2661
  },
2290
2662
  paneCollapseButton: {
2291
- margin: `0 0 0 ${tokens.spacingHorizontalXS}`,
2663
+ padding: `0 0 0 ${tokens.spacingHorizontalXS}`,
2664
+ borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
2665
+ },
2666
+ paneCollapseButtonWithBorder: {
2667
+ borderLeft: `1px solid ${tokens.colorNeutralStroke2}`,
2292
2668
  },
2293
2669
  collapseMenuPopover: {
2294
2670
  minWidth: 0,
@@ -2330,7 +2706,6 @@ const useStyles$M = makeStyles({
2330
2706
  height: "36px",
2331
2707
  backgroundColor: tokens.colorNeutralBackground1,
2332
2708
  color: tokens.colorNeutralForeground1,
2333
- border: `1px solid ${tokens.colorNeutralStroke2}`,
2334
2709
  },
2335
2710
  paneHeaderText: {
2336
2711
  flex: 1,
@@ -2349,29 +2724,33 @@ const useStyles$M = makeStyles({
2349
2724
  },
2350
2725
  tabToolbar: {
2351
2726
  padding: 0,
2727
+ borderLeft: `1px solid ${tokens.colorNeutralStroke2}`,
2728
+ borderRight: `1px solid ${tokens.colorNeutralStroke2}`,
2352
2729
  },
2353
2730
  tab: {
2354
2731
  display: "flex",
2355
2732
  height: "100%",
2356
- width: "36px",
2733
+ boxSizing: "border-box",
2357
2734
  justifyContent: "center",
2358
- borderTopLeftRadius: tokens.borderRadiusMedium,
2359
- borderTopRightRadius: tokens.borderRadiusMedium,
2735
+ border: `1px solid ${tokens.colorNeutralStroke2}`,
2736
+ borderTop: "none",
2737
+ },
2738
+ firstTab: {
2739
+ borderLeftColor: "transparent",
2740
+ },
2741
+ lastTab: {
2742
+ borderRightColor: "transparent",
2360
2743
  },
2361
2744
  selectedTab: {
2362
- backgroundColor: tokens.colorNeutralBackground1,
2363
- color: tokens.colorNeutralForeground1,
2364
- border: `1px solid ${tokens.colorNeutralStroke2}`,
2365
2745
  borderBottom: "none",
2366
2746
  },
2367
2747
  unselectedTab: {
2368
- backgroundColor: "transparent",
2748
+ borderLeftColor: "transparent",
2749
+ borderRightColor: "transparent",
2369
2750
  },
2370
2751
  tabRadioButton: {
2371
2752
  backgroundColor: "transparent",
2372
- },
2373
- selectedTabIcon: {
2374
- color: "inherit",
2753
+ borderRadius: 0,
2375
2754
  },
2376
2755
  resizer: {
2377
2756
  width: "8px",
@@ -2435,19 +2814,18 @@ const Toolbar = ({ location, components }) => {
2435
2814
  const classes = useStyles$M();
2436
2815
  const leftComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "left"), [components]);
2437
2816
  const rightComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "right"), [components]);
2438
- return (jsx(Fragment, { children: components.length > 0 && (jsxs("div", { className: `${classes.bar} ${location === "top" ? classes.barTop : null}`, children: [jsx("div", { className: classes.barLeft, children: leftComponents.map((entry) => (jsx(ToolbarItem, { verticalLocation: location, horizontalLocation: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) }), jsx("div", { className: classes.barRight, children: rightComponents.map((entry) => (jsx(ToolbarItem, { verticalLocation: location, horizontalLocation: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) })] })) }));
2817
+ return (jsx(Fragment, { children: components.length > 0 && (jsxs("div", { className: `${classes.bar} ${location === "top" ? classes.barTop : classes.barBottom}`, children: [jsx("div", { className: classes.barLeft, children: leftComponents.map((entry) => (jsx(ToolbarItem, { verticalLocation: location, horizontalLocation: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) }), jsx("div", { className: classes.barRight, children: rightComponents.map((entry) => (jsx(ToolbarItem, { verticalLocation: location, horizontalLocation: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) })] })) }));
2439
2818
  };
2440
2819
  // This is a wrapper for a tab in a side pane that simply adds a teaching moment, which is useful for dynamically added items, possibly from extensions.
2441
2820
  const SidePaneTab = (props) => {
2442
- const { location, id, isSelected, dockOptions,
2821
+ const { location, id, isSelected, isFirst, isLast, dockOptions,
2443
2822
  // eslint-disable-next-line @typescript-eslint/naming-convention
2444
2823
  icon: Icon, title, suppressTeachingMoment, } = props;
2445
2824
  const classes = useStyles$M();
2446
2825
  const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Pane/${location}/${title ?? id}`), [title, id]);
2447
2826
  const teachingMoment = useTeachingMoment(suppressTeachingMoment);
2448
- const tabClass = mergeClasses(classes.tab, isSelected ? classes.selectedTab : classes.unselectedTab);
2827
+ const tabClass = mergeClasses(classes.tab, isSelected ? classes.selectedTab : classes.unselectedTab, isFirst ? classes.firstTab : undefined, isLast ? classes.lastTab : undefined);
2449
2828
  return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay && !suppressTeachingMoment, title: title ?? "Extension", description: `The "${title ?? id}" extension can be accessed here.` }), jsx("div", { className: tabClass, children: jsx(DockMenu, { openOnContext: true, sidePaneId: id, dockOptions: dockOptions, children: jsx(Tooltip, { content: title ?? id, children: jsx(ToolbarRadioButton, { ref: teachingMoment.targetRef, appearance: "transparent", className: classes.tabRadioButton, name: "selectedTab", value: id, icon: {
2450
- className: isSelected ? classes.selectedTabIcon : undefined,
2451
2829
  children: jsx(Icon, {}),
2452
2830
  } }) }) }) })] }));
2453
2831
  };
@@ -2548,17 +2926,17 @@ function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane,
2548
2926
  }, [childWindow, location]);
2549
2927
  const expandCollapseButton = useMemo(() => {
2550
2928
  const expandCollapseIcon = location === "left" ? collapsed ? jsx(PanelLeftExpandRegular, {}) : jsx(PanelLeftContractRegular, {}) : collapsed ? jsx(PanelRightExpandRegular, {}) : jsx(PanelRightContractRegular, {});
2551
- return (jsxs(Menu, { positioning: "below-end", children: [jsx(MenuTrigger, { disableButtonEnhancement: true, children: (triggerProps) => (jsx(Tooltip, { content: collapsed ? "Show Side Pane" : "Hide Side Pane", children: jsx(SplitButton, { className: classes.paneCollapseButton, menuButton: triggerProps, primaryActionButton: { onClick: onExpandCollapseClick }, size: "small", appearance: "transparent", icon: expandCollapseIcon }) })) }), jsx(MenuPopover, { className: classes.collapseMenuPopover, children: jsx(MenuList, { children: jsx(MenuItem, { icon: jsx(PictureInPictureEnterRegular, {}), onClick: () => setUndocked(true), children: "Undock" }) }) })] }));
2929
+ return (jsxs(Menu, { positioning: "below-end", children: [jsx(MenuTrigger, { disableButtonEnhancement: true, children: (triggerProps) => (jsx(Tooltip, { content: collapsed ? "Show Side Pane" : "Hide Side Pane", children: jsx(SplitButton, { className: mergeClasses(classes.paneCollapseButton, location === "right" && toolbarMode === "compact" ? classes.paneCollapseButtonWithBorder : undefined), menuButton: triggerProps, primaryActionButton: { onClick: onExpandCollapseClick }, size: "small", appearance: "transparent", icon: expandCollapseIcon }) })) }), jsx(MenuPopover, { className: classes.collapseMenuPopover, children: jsx(MenuList, { children: jsx(MenuItem, { icon: jsx(PictureInPictureEnterRegular, {}), onClick: () => setUndocked(true), children: "Undock" }) }) })] }));
2552
2930
  }, [collapsed, onExpandCollapseClick, location]);
2553
2931
  const createPaneTabList = useCallback((paneComponents, toolbarMode, selectedTab, setSelectedTab, dockOptions) => {
2554
2932
  return (jsx(Fragment, { children: paneComponents.length > 0 && (jsxs("div", { className: `${classes.paneTabListDiv} ${location === "left" || toolbarMode === "compact" ? classes.paneTabListDivLeft : classes.paneTabListDivRight}`, children: [paneComponents.length > 1 && (jsx(Fragment, { children: jsx(Toolbar$1, { className: classes.tabToolbar, checkedValues: { selectedTab: [selectedTab?.key ?? ""] }, onCheckedValueChange: (event, data) => {
2555
2933
  const tab = paneComponents.find((entry) => entry.key === data.checkedItems[0]);
2556
2934
  setSelectedTab(tab);
2557
2935
  setCollapsed(false);
2558
- }, children: paneComponents.map((entry) => {
2936
+ }, children: paneComponents.map((entry, index) => {
2559
2937
  const isSelected = selectedTab?.key === entry.key;
2560
- return (jsx(SidePaneTab, { location: location, id: entry.key, title: entry.title, icon: entry.icon, suppressTeachingMoment: entry.suppressTeachingMoment, isSelected: isSelected && !collapsed, dockOptions: dockOptions }, entry.key));
2561
- }) }) })), toolbarMode === "full" && (jsxs(Fragment, { children: [paneComponents.length > 1 && (jsxs(Fragment, { children: [jsx(Divider, { vertical: true, inset: true, style: { minHeight: 0 } }), " "] })), jsx(Collapse, { visible: !isChildWindowOpen, orientation: "horizontal", children: expandCollapseButton })] }))] })) }));
2938
+ return (jsx(SidePaneTab, { location: location, id: entry.key, title: entry.title, icon: entry.icon, suppressTeachingMoment: entry.suppressTeachingMoment, isSelected: isSelected && !collapsed, isFirst: index === 0, isLast: index === paneComponents.length - 1, dockOptions: dockOptions }, entry.key));
2939
+ }) }) })), toolbarMode === "full" && (jsx(Collapse, { visible: !isChildWindowOpen, orientation: "horizontal", children: expandCollapseButton }))] })) }));
2562
2940
  }, [location, collapsed, isChildWindowOpen, expandCollapseButton]);
2563
2941
  // This memos the TabList to make it easy for the JSX to be inserted at the top of the pane (in "compact" mode) or returned to the caller to be used in the toolbar (in "full" mode).
2564
2942
  const topPaneTabList = useMemo(() => createPaneTabList(topPanes, toolbarMode, topSelectedTab, setTopSelectedTab, validTopDockOptions), [createPaneTabList, topPanes, toolbarMode, topSelectedTab]);
@@ -2939,7 +3317,7 @@ const PropertiesServiceDefinition = {
2939
3317
  setPendingHighlight(undefined);
2940
3318
  }
2941
3319
  }, [pendingHighlight]);
2942
- return (jsx(PropertyContext.Provider, { value: { onPropertyChanged }, children: jsx(PropertiesPane, { sections: sections, sectionContent: applicableContent, context: entity, sectionsRef: sectionsRef }) }));
3320
+ return (jsx(PropertyContext.Provider, { value: { onPropertyChanged }, children: jsx(PropertiesPane, { uniqueId: "Properties", sections: sections, sectionContent: applicableContent, context: entity, sectionsRef: sectionsRef, enablePinnedItems: true, enableHiddenItems: true, enableSearchItems: true }) }));
2943
3321
  },
2944
3322
  });
2945
3323
  return {
@@ -3807,7 +4185,7 @@ const DebugServiceDefinition = {
3807
4185
  const sections = useOrderedObservableCollection(sectionsCollection);
3808
4186
  const sectionContent = useObservableCollection(sectionContentCollection);
3809
4187
  const scene = useObservableState(() => sceneContext.currentScene, sceneContext.currentSceneObservable);
3810
- return jsx(Fragment, { children: scene && jsx(DebugPane, { sections: sections, sectionContent: sectionContent, context: scene }) });
4188
+ return (jsx(Fragment, { children: scene && (jsx(DebugPane, { uniqueId: "Debug", sections: sections, sectionContent: sectionContent, context: scene, enablePinnedItems: true, enableHiddenItems: true, enableSearchItems: true })) }));
3811
4189
  },
3812
4190
  });
3813
4191
  return {
@@ -3825,7 +4203,7 @@ const DebugServiceDefinition = {
3825
4203
  */
3826
4204
  const ButtonLine = (props) => {
3827
4205
  ButtonLine.displayName = "ButtonLine";
3828
- return (jsx(LineContainer, { children: jsx(Button, { ...props }) }));
4206
+ return (jsx(LineContainer, { uniqueId: props.uniqueId ?? props.label, children: jsx(Button, { ...props }) }));
3829
4207
  };
3830
4208
 
3831
4209
  const SettingsServiceIdentity = Symbol("SettingsService");
@@ -4022,7 +4400,7 @@ const UploadButton = (props) => {
4022
4400
  */
4023
4401
  const FileUploadLine = ({ onClick, label, accept, ...buttonProps }) => {
4024
4402
  FileUploadLine.displayName = "FileUploadLine";
4025
- return (jsx(LineContainer, { children: jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
4403
+ return (jsx(LineContainer, { uniqueId: label, children: jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
4026
4404
  };
4027
4405
 
4028
4406
  /**
@@ -5799,7 +6177,7 @@ const PerformanceStats = ({ context: scene }) => {
5799
6177
  window.addEventListener("resize", handleResize);
5800
6178
  return () => window.removeEventListener("resize", handleResize);
5801
6179
  }, [onResize]);
5802
- return (jsxs(Fragment, { children: [!isOpen && jsx(ButtonLine, { label: "Open Realtime Perf Viewer", onClick: onPerformanceButtonClick }), !isOpen && jsx(FileUploadLine, { label: "Load Perf Viewer using CSV", accept: ".csv", onClick: onLoadClick }), jsx(ButtonLine, { label: "Export Perf to CSV", icon: ArrowDownloadRegular, onClick: onExportClick }), !isOpen && jsx(ButtonLine, { label: isRecording ? "Stop Recording" : "Begin Recording", icon: isRecording ? StopRegular : RecordRegular, onClick: onToggleRecording }), jsx(ChildWindow, { id: "performance-viewer", imperativeRef: childWindowRef, onOpenChange: (open) => !open && onClosePerformanceViewer(), children: performanceCollector && (jsx(PerformanceViewer, { scene: scene, layoutObservable: layoutObservable, returnToLiveObservable: returnToLiveObservable, performanceCollector: performanceCollector, initialGraphSize: InitialGraphSize })) })] }));
6180
+ return (jsxs(Fragment, { children: [!isOpen && jsx(ButtonLine, { label: "Open Realtime Perf Viewer", onClick: onPerformanceButtonClick }), !isOpen && jsx(FileUploadLine, { label: "Load Perf Viewer using CSV", accept: ".csv", onClick: onLoadClick }), jsx(ButtonLine, { label: "Export Perf to CSV", icon: ArrowDownloadRegular, onClick: onExportClick }), !isOpen && (jsx(ButtonLine, { uniqueId: "Start/Stop", label: isRecording ? "Stop Recording" : "Begin Recording", icon: isRecording ? StopRegular : RecordRegular, onClick: onToggleRecording })), jsx(ChildWindow, { id: "performance-viewer", imperativeRef: childWindowRef, onOpenChange: (open) => !open && onClosePerformanceViewer(), children: performanceCollector && (jsx(PerformanceViewer, { scene: scene, layoutObservable: layoutObservable, returnToLiveObservable: returnToLiveObservable, performanceCollector: performanceCollector, initialGraphSize: InitialGraphSize })) })] }));
5803
6181
  };
5804
6182
 
5805
6183
  /**
@@ -5869,7 +6247,7 @@ const StatsServiceDefinition = {
5869
6247
  const sections = useOrderedObservableCollection(sectionsCollection);
5870
6248
  const sectionContent = useObservableCollection(sectionContentCollection);
5871
6249
  const scene = useObservableState(() => sceneContext.currentScene, sceneContext.currentSceneObservable);
5872
- return jsx(Fragment, { children: scene && jsx(StatsPane, { sections: sections, sectionContent: sectionContent, context: scene }) });
6250
+ return (jsx(Fragment, { children: scene && (jsx(StatsPane, { uniqueId: "Statistics", sections: sections, sectionContent: sectionContent, context: scene, enablePinnedItems: true, enableHiddenItems: true, enableSearchItems: true })) }));
5873
6251
  },
5874
6252
  });
5875
6253
  // Default/built-in sections.
@@ -5958,7 +6336,7 @@ const ToolsServiceDefinition = {
5958
6336
  const sections = useOrderedObservableCollection(sectionsCollection);
5959
6337
  const sectionContent = useObservableCollection(sectionContentCollection);
5960
6338
  const scene = useObservableState(() => sceneContext.currentScene, sceneContext.currentSceneObservable);
5961
- return scene && jsx(ToolsPane, { sections: sections, sectionContent: sectionContent, context: scene });
6339
+ return (scene && (jsx(ToolsPane, { uniqueId: "Tools", sections: sections, sectionContent: sectionContent, context: scene, enablePinnedItems: true, enableHiddenItems: true, enableSearchItems: true })));
5962
6340
  },
5963
6341
  });
5964
6342
  }
@@ -5986,7 +6364,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
5986
6364
  keywords: ["creation", "tools"],
5987
6365
  ...BabylonWebResources,
5988
6366
  author: { name: "Babylon.js", forumUserName: "" },
5989
- getExtensionModuleAsync: async () => await import('./quickCreateToolsService-B55TQEXK.js'),
6367
+ getExtensionModuleAsync: async () => await import('./quickCreateToolsService-B4U-3oma.js'),
5990
6368
  },
5991
6369
  {
5992
6370
  name: "Reflector",
@@ -5994,7 +6372,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
5994
6372
  keywords: ["reflector", "bridge", "sync", "sandbox", "tools"],
5995
6373
  ...BabylonWebResources,
5996
6374
  author: { name: "Babylon.js", forumUserName: "" },
5997
- getExtensionModuleAsync: async () => await import('./reflectorService-BHVk1B6L.js'),
6375
+ getExtensionModuleAsync: async () => await import('./reflectorService-ozofO4uE.js'),
5998
6376
  },
5999
6377
  ]);
6000
6378
 
@@ -6824,7 +7202,7 @@ function MakeModularTool(options) {
6824
7202
  });
6825
7203
  // Register the extension list service (for browsing/installing extensions) if extension feeds are provided.
6826
7204
  if (extensionFeeds.length > 0) {
6827
- const { ExtensionListServiceDefinition } = await import('./extensionsListService-1OhC4MZF.js');
7205
+ const { ExtensionListServiceDefinition } = await import('./extensionsListService-DnGdJhHc.js');
6828
7206
  await serviceContainer.addServiceAsync(ExtensionListServiceDefinition);
6829
7207
  }
6830
7208
  // Register the theme selector service (for selecting the theme) if theming is configured.
@@ -10794,7 +11172,7 @@ const AnimationGroupControlProperties = (props) => {
10794
11172
  return currentFrameHolder ? currentFrameHolder.currentFrame : undefined;
10795
11173
  }, [currentFrameHolder]), isPlaying ? animationGroup.getScene().onBeforeRenderObservable : null);
10796
11174
  const enableBlending = useProperty(animationGroup, "enableBlending");
10797
- return (jsxs(Fragment, { children: [jsx(ButtonLine, { label: isPlaying ? "Pause" : "Play", onClick: () => (isPlaying ? animationGroup.pause() : animationGroup.play(true)) }), jsx(ButtonLine, { label: "Stop", onClick: () => animationGroup.stop() }), jsx(CurveEditorButton, { scene: scene, target: null, animations: targetedAnimations, rootAnimationGroup: animationGroup, title: animationGroup.name, useTargetAnimations: true }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Speed Ratio", min: 0, max: 10, step: 0.1, target: animationGroup, propertyKey: "speedRatio" }), currentFrameHolder && currentFrame !== undefined ? (jsx(SyncedSliderPropertyLine, { label: "Current Frame", min: animationGroup.from, max: animationGroup.to, step: (animationGroup.to - animationGroup.from) / 1000.0, value: currentFrame, onChange: (value) => {
11175
+ return (jsxs(Fragment, { children: [jsx(ButtonLine, { uniqueId: "Start/Stop", label: isPlaying ? "Pause" : "Play", onClick: () => (isPlaying ? animationGroup.pause() : animationGroup.play(true)) }), jsx(ButtonLine, { label: "Stop", onClick: () => animationGroup.stop() }), jsx(CurveEditorButton, { scene: scene, target: null, animations: targetedAnimations, rootAnimationGroup: animationGroup, title: animationGroup.name, useTargetAnimations: true }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Speed Ratio", min: 0, max: 10, step: 0.1, target: animationGroup, propertyKey: "speedRatio" }), currentFrameHolder && currentFrame !== undefined ? (jsx(SyncedSliderPropertyLine, { label: "Current Frame", min: animationGroup.from, max: animationGroup.to, step: (animationGroup.to - animationGroup.from) / 1000.0, value: currentFrame, onChange: (value) => {
10798
11176
  if (!animationGroup.isPlaying) {
10799
11177
  animationGroup.play(true);
10800
11178
  animationGroup.goToFrame(value);
@@ -10856,9 +11234,9 @@ const useClasses = makeStyles({
10856
11234
  });
10857
11235
  const MessageBar = (props) => {
10858
11236
  MessageBar.displayName = "MessageBar";
10859
- const { message, title, intent, docLink } = props;
11237
+ const { message, title, intent, docLink, staticItem } = props;
10860
11238
  const classes = useClasses();
10861
- return (jsx("div", { className: classes.container, children: jsx(MessageBar$1, { intent: intent, layout: "multiline", children: jsxs(MessageBarBody, { children: [title && jsx(MessageBarTitle, { children: title }), message, docLink && (jsxs(Fragment, { children: [" - ", jsx(Link, { url: docLink, value: "Learn More" })] }))] }) }) }));
11239
+ return (jsx(AccordionSectionItem, { uniqueId: title ?? message, staticItem: staticItem ?? true, children: jsx("div", { className: classes.container, children: jsx(MessageBar$1, { intent: intent, layout: "multiline", children: jsxs(MessageBarBody, { children: [title && jsx(MessageBarTitle, { children: title }), message, docLink && (jsxs(Fragment, { children: [" - ", jsx(Link, { url: docLink, value: "Learn More" })] }))] }) }) }) }));
10862
11240
  };
10863
11241
 
10864
11242
  const AnimationsProperties = (props) => {
@@ -10903,7 +11281,7 @@ const AnimationsProperties = (props) => {
10903
11281
  }
10904
11282
  } }), jsx(SyncedSliderPropertyLine, { label: "Current Frame", value: currentFrame, min: mainAnimatable.fromFrame, max: mainAnimatable.toFrame, step: (mainAnimatable.toFrame - mainAnimatable.fromFrame) / 1000, onChange: (value) => {
10905
11283
  mainAnimatable.goToFrame(value);
10906
- } })] }), expandByDefault: true }) })), hasAnimations && (jsx(ButtonLine, { label: isPlaying ? "Stop Animation" : "Play Animation", onClick: () => {
11284
+ } })] }), expandByDefault: true }) })), hasAnimations && (jsx(ButtonLine, { uniqueId: "Start/Stop", label: isPlaying ? "Stop Animation" : "Play Animation", onClick: () => {
10907
11285
  if (isPlaying) {
10908
11286
  scene.stopAnimation(entity);
10909
11287
  }
@@ -11046,7 +11424,7 @@ const SoundCommandProperties = (props) => {
11046
11424
  const { sound } = props;
11047
11425
  const soundState = useSoundState(sound);
11048
11426
  const volume = useObservableState(useCallback(() => sound.getVolume(), [sound]), useInterceptObservable("function", sound, "setVolume"));
11049
- return (jsxs(Fragment, { children: [jsx(ButtonLine, { label: soundState === "Playing" ? "Pause" : "Play", icon: soundState === "Playing" ? PauseRegular : PlayRegular, onClick: () => {
11427
+ return (jsxs(Fragment, { children: [jsx(ButtonLine, { uniqueId: "Start/Stop", label: soundState === "Playing" ? "Pause" : "Play", icon: soundState === "Playing" ? PauseRegular : PlayRegular, onClick: () => {
11050
11428
  if (soundState === "Playing") {
11051
11429
  sound.pause();
11052
11430
  }
@@ -12681,7 +13059,7 @@ const PBRBaseMaterialChannelsProperties = (props) => {
12681
13059
  const { material, selectionService } = props;
12682
13060
  const scene = material.getScene();
12683
13061
  const selectEntity = (entity) => (selectionService.selectedEntity = entity);
12684
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Albedo", target: material, propertyKey: "_albedoTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Base Weight", target: material, propertyKey: "_baseWeightTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughnessTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Metallic Roughness", target: material, propertyKey: "_metallicTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflection", target: material, propertyKey: "_reflectionTexture", scene: scene, cubeOnly: true, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Refraction", target: material.subSurface, propertyKey: "refractionTexture", propertyPath: "subSurface.refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflectivity", target: material, propertyKey: "_reflectivityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Micro Surface", target: material, propertyKey: "_microSurfaceTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material, propertyKey: "_bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Emissive", target: material, propertyKey: "_emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Opacity", target: material, propertyKey: "_opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Ambient", target: material, propertyKey: "_ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Lightmap", target: material, propertyKey: "_lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Detailmap", target: material.detailMap, propertyKey: "texture", propertyPath: "detailMap.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Lightmap as Shadowmap", target: material, propertyKey: "_useLightmapAsShadowmap" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Detailmap", target: material.detailMap, propertyKey: "isEnabled", propertyPath: "detailMap.isEnabled" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Decalmap", target: material.decalMap, propertyKey: "isEnabled", propertyPath: "decalMap.isEnabled" })] }));
13062
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Albedo", target: material, propertyKey: "_albedoTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Base Weight", target: material, propertyKey: "_baseWeightTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughnessTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Metallic Roughness", target: material, propertyKey: "_metallicTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, uniqueId: "PBRBaseMaterialChannels_Reflection", label: "Reflection", target: material, propertyKey: "_reflectionTexture", scene: scene, cubeOnly: true, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Refraction", target: material.subSurface, propertyKey: "refractionTexture", propertyPath: "subSurface.refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflectivity", target: material, propertyKey: "_reflectivityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Micro Surface", target: material, propertyKey: "_microSurfaceTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material, propertyKey: "_bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Emissive", target: material, propertyKey: "_emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Opacity", target: material, propertyKey: "_opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Ambient", target: material, propertyKey: "_ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Lightmap", target: material, propertyKey: "_lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Detailmap", target: material.detailMap, propertyKey: "texture", propertyPath: "detailMap.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Lightmap as Shadowmap", target: material, propertyKey: "_useLightmapAsShadowmap" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Detailmap", target: material.detailMap, propertyKey: "isEnabled", propertyPath: "detailMap.isEnabled" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Decalmap", target: material.decalMap, propertyKey: "isEnabled", propertyPath: "decalMap.isEnabled" })] }));
12685
13063
  };
12686
13064
  const PBRBaseMaterialLightingAndColorProperties = (props) => {
12687
13065
  const { material } = props;
@@ -12691,7 +13069,7 @@ const PBRBaseMaterialMetallicWorkflowProperties = (props) => {
12691
13069
  const { material, selectionService } = props;
12692
13070
  const scene = material.getScene();
12693
13071
  const selectEntity = (entity) => (selectionService.selectedEntity = entity);
12694
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Metallic", target: material, propertyKey: "_metallic", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Roughness", target: material, propertyKey: "_roughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Index of Refraction", target: material.subSurface, propertyKey: "indexOfRefraction", propertyPath: "subSurface.indexOfRefraction", min: 1, max: 3, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "F0 Factor", target: material, propertyKey: "_metallicF0Factor", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Reflectance Color", target: material, propertyKey: "_metallicReflectanceColor", isLinearMode: true }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Metallic Only", description: "Use only metallic from MetallicReflectance texture", target: material, propertyKey: "_useOnlyMetallicFromMetallicReflectanceTexture" }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Metallic Reflectance", target: material, propertyKey: "_metallicReflectanceTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflectance", target: material, propertyKey: "_reflectanceTexture", scene: scene, onLink: selectEntity, defaultValue: null })] }));
13072
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Metallic", target: material, propertyKey: "_metallic", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, uniqueId: "PBRBaseMaterialMetallicWorkflow_Roughness", label: "Roughness", target: material, propertyKey: "_roughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Index of Refraction", target: material.subSurface, propertyKey: "indexOfRefraction", propertyPath: "subSurface.indexOfRefraction", min: 1, max: 3, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "F0 Factor", target: material, propertyKey: "_metallicF0Factor", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Reflectance Color", target: material, propertyKey: "_metallicReflectanceColor", isLinearMode: true }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Metallic Only", description: "Use only metallic from MetallicReflectance texture", target: material, propertyKey: "_useOnlyMetallicFromMetallicReflectanceTexture" }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Metallic Reflectance", target: material, propertyKey: "_metallicReflectanceTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflectance", target: material, propertyKey: "_reflectanceTexture", scene: scene, onLink: selectEntity, defaultValue: null })] }));
12695
13073
  };
12696
13074
  const PBRBaseMaterialClearCoatProperties = (props) => {
12697
13075
  const { material, selectionService } = props;
@@ -12700,7 +13078,7 @@ const PBRBaseMaterialClearCoatProperties = (props) => {
12700
13078
  const isEnabled = useProperty(material.clearCoat, "isEnabled");
12701
13079
  const isTintEnabled = useProperty(material.clearCoat, "isTintEnabled");
12702
13080
  const bumpTexture = useProperty(material.clearCoat, "bumpTexture");
12703
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Enabled", target: material.clearCoat, propertyKey: "isEnabled", propertyPath: "clearCoat.isEnabled" }), jsxs(Collapse, { visible: isEnabled, children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Intensity", target: material.clearCoat, propertyKey: "intensity", propertyPath: "clearCoat.intensity", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Roughness", target: material.clearCoat, propertyKey: "roughness", propertyPath: "clearCoat.roughness", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "IOR", description: "Index of Refraction", target: material.clearCoat, propertyKey: "indexOfRefraction", propertyPath: "clearCoat.indexOfRefraction", min: 1, max: 3, step: 0.01 }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Remap F0", target: material.clearCoat, propertyKey: "remapF0OnInterfaceChange", propertyPath: "clearCoat.remapF0OnInterfaceChange" }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Clear Coat", target: material.clearCoat, propertyKey: "texture", propertyPath: "clearCoat.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Roughness", target: material.clearCoat, propertyKey: "textureRoughness", propertyPath: "clearCoat.textureRoughness", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material.clearCoat, propertyKey: "bumpTexture", propertyPath: "clearCoat.bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(Collapse, { visible: bumpTexture !== null, children: jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Bump Strength", target: bumpTexture, propertyKey: "level", propertyPath: "clearCoat.bumpTexture.level", min: 0, max: 2, step: 0.01 }) }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness from Main Texture", target: material.clearCoat, propertyKey: "useRoughnessFromMainTexture", propertyPath: "clearCoat.useRoughnessFromMainTexture" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Tint", target: material.clearCoat, propertyKey: "isTintEnabled", propertyPath: "clearCoat.isTintEnabled" }), jsxs(Collapse, { visible: isTintEnabled, children: [jsx(BoundProperty, { component: Color3PropertyLine, label: "Tint Color", target: material.clearCoat, propertyKey: "tintColor", propertyPath: "clearCoat.tintColor", isLinearMode: true }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "At Distance", target: material.clearCoat, propertyKey: "tintColorAtDistance", propertyPath: "clearCoat.tintColorAtDistance", min: 0, max: 20, step: 0.1 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Tint Thickness", target: material.clearCoat, propertyKey: "tintThickness", propertyPath: "clearCoat.tintThickness", min: 0, max: 20, step: 0.1 }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Tint", target: material.clearCoat, propertyKey: "tintTexture", propertyPath: "clearCoat.tintTexture", scene: scene, onLink: selectEntity, defaultValue: null })] })] })] }));
13081
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Enabled", target: material.clearCoat, propertyKey: "isEnabled", propertyPath: "clearCoat.isEnabled" }), jsxs(Collapse, { visible: isEnabled, children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Intensity", target: material.clearCoat, propertyKey: "intensity", propertyPath: "clearCoat.intensity", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, uniqueId: "PBRBaseMaterialClearCoat_Roughness_1", label: "Roughness", target: material.clearCoat, propertyKey: "roughness", propertyPath: "clearCoat.roughness", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "IOR", description: "Index of Refraction", target: material.clearCoat, propertyKey: "indexOfRefraction", propertyPath: "clearCoat.indexOfRefraction", min: 1, max: 3, step: 0.01 }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Remap F0", target: material.clearCoat, propertyKey: "remapF0OnInterfaceChange", propertyPath: "clearCoat.remapF0OnInterfaceChange" }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Clear Coat", target: material.clearCoat, propertyKey: "texture", propertyPath: "clearCoat.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, uniqueId: "PBRBaseMaterialClearCoat_Roughness_2", label: "Roughness", target: material.clearCoat, propertyKey: "textureRoughness", propertyPath: "clearCoat.textureRoughness", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material.clearCoat, propertyKey: "bumpTexture", propertyPath: "clearCoat.bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(Collapse, { visible: bumpTexture !== null, children: jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Bump Strength", target: bumpTexture, propertyKey: "level", propertyPath: "clearCoat.bumpTexture.level", min: 0, max: 2, step: 0.01 }) }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness from Main Texture", target: material.clearCoat, propertyKey: "useRoughnessFromMainTexture", propertyPath: "clearCoat.useRoughnessFromMainTexture" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Tint", target: material.clearCoat, propertyKey: "isTintEnabled", propertyPath: "clearCoat.isTintEnabled" }), jsxs(Collapse, { visible: isTintEnabled, children: [jsx(BoundProperty, { component: Color3PropertyLine, label: "Tint Color", target: material.clearCoat, propertyKey: "tintColor", propertyPath: "clearCoat.tintColor", isLinearMode: true }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "At Distance", target: material.clearCoat, propertyKey: "tintColorAtDistance", propertyPath: "clearCoat.tintColorAtDistance", min: 0, max: 20, step: 0.1 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Tint Thickness", target: material.clearCoat, propertyKey: "tintThickness", propertyPath: "clearCoat.tintThickness", min: 0, max: 20, step: 0.1 }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Tint", target: material.clearCoat, propertyKey: "tintTexture", propertyPath: "clearCoat.tintTexture", scene: scene, onLink: selectEntity, defaultValue: null })] })] })] }));
12704
13082
  };
12705
13083
  const PBRBaseMaterialIridescenceProperties = (props) => {
12706
13084
  const { material, selectionService } = props;
@@ -12722,7 +13100,7 @@ const PBRBaseMaterialSheenProperties = (props) => {
12722
13100
  const selectEntity = (entity) => (selectionService.selectedEntity = entity);
12723
13101
  const isEnabled = useProperty(material.sheen, "isEnabled");
12724
13102
  const useRoughness = useProperty(material.sheen, "_useRoughness");
12725
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Enabled", target: material.sheen, propertyKey: "isEnabled", propertyPath: "sheen.isEnabled" }), jsxs(Collapse, { visible: isEnabled, children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Link to Albedo", target: material.sheen, propertyKey: "linkSheenWithAlbedo", propertyPath: "sheen.linkSheenWithAlbedo" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Intensity", target: material.sheen, propertyKey: "intensity", propertyPath: "sheen.intensity", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Color", target: material.sheen, propertyKey: "color", propertyPath: "sheen.color", isLinearMode: true }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Sheen", target: material.sheen, propertyKey: "texture", propertyPath: "sheen.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Roughness", target: material.sheen, propertyKey: "textureRoughness", propertyPath: "sheen.textureRoughness", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness", target: material.sheen, propertyKey: "_useRoughness", propertyPath: "sheen._useRoughness" }), jsx(Collapse, { visible: useRoughness, children: jsx(BoundProperty, { nullable: true, component: SyncedSliderPropertyLine, label: "Roughness", target: material.sheen, propertyKey: "roughness", propertyPath: "sheen.roughness", defaultValue: 0, min: 0, max: 1, step: 0.01 }) }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness from Main Texture", target: material.sheen, propertyKey: "useRoughnessFromMainTexture", propertyPath: "sheen.useRoughnessFromMainTexture" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Albedo Scaling", target: material.sheen, propertyKey: "albedoScaling", propertyPath: "sheen.albedoScaling" })] })] }));
13103
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Enabled", target: material.sheen, propertyKey: "isEnabled", propertyPath: "sheen.isEnabled" }), jsxs(Collapse, { visible: isEnabled, children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Link to Albedo", target: material.sheen, propertyKey: "linkSheenWithAlbedo", propertyPath: "sheen.linkSheenWithAlbedo" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Intensity", target: material.sheen, propertyKey: "intensity", propertyPath: "sheen.intensity", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Color", target: material.sheen, propertyKey: "color", propertyPath: "sheen.color", isLinearMode: true }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Sheen", target: material.sheen, propertyKey: "texture", propertyPath: "sheen.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, uniqueId: "PBRBaseMaterialSheen_Roughness_1", label: "Roughness", target: material.sheen, propertyKey: "textureRoughness", propertyPath: "sheen.textureRoughness", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness", target: material.sheen, propertyKey: "_useRoughness", propertyPath: "sheen._useRoughness" }), jsx(Collapse, { visible: useRoughness, children: jsx(BoundProperty, { nullable: true, component: SyncedSliderPropertyLine, uniqueId: "PBRBaseMaterialSheen_Roughness_2", label: "Roughness", target: material.sheen, propertyKey: "roughness", propertyPath: "sheen.roughness", defaultValue: 0, min: 0, max: 1, step: 0.01 }) }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness from Main Texture", target: material.sheen, propertyKey: "useRoughnessFromMainTexture", propertyPath: "sheen.useRoughnessFromMainTexture" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Albedo Scaling", target: material.sheen, propertyKey: "albedoScaling", propertyPath: "sheen.albedoScaling" })] })] }));
12726
13104
  };
12727
13105
  const PBRBaseMaterialSubSurfaceProperties = (props) => {
12728
13106
  const { material, selectionService } = props;
@@ -12769,7 +13147,7 @@ const StandardMaterialTexturesProperties = (props) => {
12769
13147
  const { material, selectionService } = props;
12770
13148
  const scene = material.getScene();
12771
13149
  const selectEntity = (entity) => (selectionService.selectedEntity = entity);
12772
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Diffuse", target: material, propertyKey: "diffuseTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Specular", target: material, propertyKey: "specularTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflection", target: material, propertyKey: "reflectionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Refraction", target: material, propertyKey: "refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Emissive", target: material, propertyKey: "emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material, propertyKey: "bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Opacity", target: material, propertyKey: "opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Ambient", target: material, propertyKey: "ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Lightmap", target: material, propertyKey: "lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Detailmap", target: material.detailMap, propertyKey: "texture", propertyPath: "detailMap.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Lightmap as Shadowmap", target: material, propertyKey: "useLightmapAsShadowmap" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Detailmap", target: material.detailMap, propertyKey: "isEnabled", propertyPath: "detailMap.isEnabled" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Decalmap", target: material.decalMap, propertyKey: "isEnabled", propertyPath: "decalMap.isEnabled" })] }));
13150
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Diffuse", target: material, propertyKey: "diffuseTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Specular", target: material, propertyKey: "specularTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, uniqueId: "StandardMaterialTextures_Reflection", label: "Reflection", target: material, propertyKey: "reflectionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Refraction", target: material, propertyKey: "refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Emissive", target: material, propertyKey: "emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material, propertyKey: "bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Opacity", target: material, propertyKey: "opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Ambient", target: material, propertyKey: "ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Lightmap", target: material, propertyKey: "lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Detailmap", target: material.detailMap, propertyKey: "texture", propertyPath: "detailMap.texture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Lightmap as Shadowmap", target: material, propertyKey: "useLightmapAsShadowmap" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Detailmap", target: material.detailMap, propertyKey: "isEnabled", propertyPath: "detailMap.isEnabled" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Decalmap", target: material.decalMap, propertyKey: "isEnabled", propertyPath: "decalMap.isEnabled" })] }));
12773
13151
  };
12774
13152
  /**
12775
13153
  * Displays the levels properties of a standard material.
@@ -13171,14 +13549,14 @@ const MetadataProperties = (props) => {
13171
13549
  const [editedMetadata, setEditedMetadata] = useState(stringifiedMetadata);
13172
13550
  const isEditedMetadataJSON = useMemo(() => IsParsable(editedMetadata), [editedMetadata]);
13173
13551
  const unformattedEditedMetadata = useMemo(() => Restringify(editedMetadata, false), [editedMetadata]);
13174
- return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Property Type", value: metadataType }), jsx(Collapse, { visible: canPreventObjectCorruption, children: jsx(SwitchPropertyLine, { label: "Prevent Object Corruption", value: isReadonly, onChange: setPreventObjectCorruption }) }), jsx(LineContainer, { children: jsx(Textarea, { disabled: isReadonly, value: editedMetadata, onChange: setEditedMetadata }) }), jsx(ButtonLine, { label: "Populate glTF extras", disabled: !!editedMetadata && (!IsParsable(editedMetadata) || HasGltfExtras(editedMetadata)), onClick: () => {
13552
+ return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Property Type", value: metadataType }), jsx(Collapse, { visible: canPreventObjectCorruption, children: jsx(SwitchPropertyLine, { label: "Prevent Object Corruption", value: isReadonly, onChange: setPreventObjectCorruption }) }), jsx(LineContainer, { uniqueId: "MetadataTextarea", children: jsx(Textarea, { disabled: isReadonly, value: editedMetadata, onChange: setEditedMetadata }) }), jsx(ButtonLine, { label: "Populate glTF extras", disabled: !!editedMetadata && (!IsParsable(editedMetadata) || HasGltfExtras(editedMetadata)), onClick: () => {
13175
13553
  const isFormatted = Restringify(editedMetadata, true) === editedMetadata;
13176
13554
  let withGLTFExtras = PopulateGLTFExtras(editedMetadata);
13177
13555
  if (isFormatted) {
13178
13556
  withGLTFExtras = Restringify(withGLTFExtras, true);
13179
13557
  }
13180
13558
  setEditedMetadata(withGLTFExtras);
13181
- } }), jsx(LineContainer, { children: jsxs("div", { className: classes.buttonDiv, children: [jsx(Button$1, { size: size, icon: jsx(SaveRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => SaveMetadata(entity, editedMetadata), children: jsx(Body1, { children: "Save" }) }), jsx(Tooltip$1, { content: "Undo Changes", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(ArrowUndoRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => setEditedMetadata(stringifiedMetadata) }) }), jsx(Tooltip$1, { content: "Format (Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesRegular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, true)) }) }), jsx(Tooltip$1, { content: "Clear Formatting (Undo Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesDismiss16Regular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, false)) }) })] }) })] }));
13559
+ } }), jsx(LineContainer, { uniqueId: "MetadataButtonDiv", children: jsxs("div", { className: classes.buttonDiv, children: [jsx(Button$1, { size: size, icon: jsx(SaveRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => SaveMetadata(entity, editedMetadata), children: jsx(Body1, { children: "Save" }) }), jsx(Tooltip$1, { content: "Undo Changes", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(ArrowUndoRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => setEditedMetadata(stringifiedMetadata) }) }), jsx(Tooltip$1, { content: "Format (Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesRegular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, true)) }) }), jsx(Tooltip$1, { content: "Clear Formatting (Undo Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesDismiss16Regular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, false)) }) })] }) })] }));
13182
13560
  };
13183
13561
 
13184
13562
  function IsMetadataContainer(entity) {
@@ -13628,7 +14006,7 @@ const ParticleSystemSystemProperties = (props) => {
13628
14006
  const capacity = useObservableState(() => system.getCapacity());
13629
14007
  const activeCount = useObservableState(() => system.getActiveCount(), scene?.onBeforeRenderObservable);
13630
14008
  const selectEntity = (entity) => (selectionService.selectedEntity = entity);
13631
- return (jsxs(Fragment, { children: [isCpuParticleSystem && (jsx(TextPropertyLine, { label: "Is Node Generated", description: "Indicates if the particle system was created from a node-based particle system.", value: String(isNodeGenerated) })), jsx(StringifiedPropertyLine, { label: "Capacity", description: "Maximum number of particles in the system.", value: capacity }), jsx(StringifiedPropertyLine, { label: "Active Particles", description: "Current number of active particles.", value: activeCount }), scene && !isNodeGenerated && (jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Particle Texture", target: system, propertyKey: "particleTexture", scene: scene, onLink: selectEntity, defaultValue: null })), jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Blend Mode", target: system, propertyKey: "blendMode", options: BlendModeOptions }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "World Offset", target: system, propertyKey: "worldOffset" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Gravity", target: system, propertyKey: "gravity" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Billboard", target: system, propertyKey: "isBillboardBased" }), isBillboardBased && (jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Billboard Mode", target: system, propertyKey: "billboardMode", options: ParticleBillboardModeOptions })), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Local", target: system, propertyKey: "isLocal" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Force Depth Write", target: system, propertyKey: "forceDepthWrite" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Update Speed", target: system, propertyKey: "updateSpeed", min: 0, step: 0.01 }), isCpuParticleSystem && (jsx(ButtonLine, { label: isNodeGenerated ? "Edit" : "View as Node-Based Particle System", icon: isNodeGenerated ? EditRegular : EyeRegular, onClick: async () => {
14009
+ return (jsxs(Fragment, { children: [isCpuParticleSystem && (jsx(TextPropertyLine, { label: "Is Node Generated", description: "Indicates if the particle system was created from a node-based particle system.", value: String(isNodeGenerated) })), jsx(StringifiedPropertyLine, { label: "Capacity", description: "Maximum number of particles in the system.", value: capacity }), jsx(StringifiedPropertyLine, { label: "Active Particles", description: "Current number of active particles.", value: activeCount }), scene && !isNodeGenerated && (jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Particle Texture", target: system, propertyKey: "particleTexture", scene: scene, onLink: selectEntity, defaultValue: null })), jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Blend Mode", target: system, propertyKey: "blendMode", options: BlendModeOptions }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "World Offset", target: system, propertyKey: "worldOffset" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Gravity", target: system, propertyKey: "gravity" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Billboard", target: system, propertyKey: "isBillboardBased" }), isBillboardBased && (jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Billboard Mode", target: system, propertyKey: "billboardMode", options: ParticleBillboardModeOptions })), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Local", target: system, propertyKey: "isLocal" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Force Depth Write", target: system, propertyKey: "forceDepthWrite" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Update Speed", target: system, propertyKey: "updateSpeed", min: 0, step: 0.01 }), isCpuParticleSystem && (jsx(ButtonLine, { uniqueId: "View/Edit", label: isNodeGenerated ? "Edit" : "View as Node-Based Particle System", icon: isNodeGenerated ? EditRegular : EyeRegular, onClick: async () => {
13632
14010
  const scene = system.getScene();
13633
14011
  if (!scene) {
13634
14012
  return;
@@ -15374,7 +15752,7 @@ const SceneCollisionsProperties = (props) => {
15374
15752
  };
15375
15753
  const SceneShadowsProperties = (props) => {
15376
15754
  const { scene } = props;
15377
- return (jsx(Fragment, { children: jsx(ButtonLine, { label: "Normalize scene", onClick: () => {
15755
+ return (jsx(Fragment, { children: jsx(ButtonLine, { label: "Normalize Scene", onClick: () => {
15378
15756
  for (const mesh of scene.meshes) {
15379
15757
  mesh.normalizeToUnitCube(true);
15380
15758
  mesh.computeWorldMatrix(true);
@@ -15413,7 +15791,7 @@ const SceneRenderingProperties = (props) => {
15413
15791
  scene.environmentTexture = StoredEnvironmentTexture;
15414
15792
  StoredEnvironmentTexture = null;
15415
15793
  }
15416
- } }), scene.environmentTexture && (jsx(LinkPropertyLine, { label: "Env. texture", value: scene.environmentTexture.name, onLink: () => (selectionService.selectedEntity = scene.environmentTexture) })), jsx(FileUploadLine, { label: "Update Environment Texture", accept: ".dds, .env", onClick: (files) => {
15794
+ } }), scene.environmentTexture && (jsx(LinkPropertyLine, { label: "Env. Texture", value: scene.environmentTexture.name, onLink: () => (selectionService.selectedEntity = scene.environmentTexture) })), jsx(FileUploadLine, { label: "Update Environment Texture", accept: ".dds, .env", onClick: (files) => {
15417
15795
  if (files.length > 0) {
15418
15796
  const file = files[0];
15419
15797
  const isFileDDS = file.name.toLowerCase().indexOf(".dds") > 0;
@@ -15711,7 +16089,8 @@ const SpriteManagerActionsProperties = (props) => {
15711
16089
  * @returns the 8-bit texture data
15712
16090
  */
15713
16091
  async function ApplyChannelsToTextureDataAsync(texture, width, height, face, channels, lod = 0) {
15714
- const data = await GetTextureDataAsync(texture, width, height, face, lod);
16092
+ // For cube maps, force RTT path to ensure correct face orientation and gamma correction
16093
+ const data = await GetTextureDataAsync(texture, width, height, face, lod, texture.isCube);
15715
16094
  if (!channels.R || !channels.G || !channels.B || !channels.A) {
15716
16095
  for (let i = 0; i < width * height * 4; i += 4) {
15717
16096
  // If alpha is the only channel, just display alpha across all channels
@@ -15803,9 +16182,11 @@ const useStyles$9 = makeStyles({
15803
16182
  textOverflow: "ellipsis",
15804
16183
  },
15805
16184
  preview: {
15806
- border: `1px solid ${tokens.colorNeutralStroke1}`,
16185
+ outline: `1px solid ${tokens.colorNeutralStroke1}`,
15807
16186
  display: "block",
15808
16187
  objectFit: "contain",
16188
+ // Checkerboard background to show transparency
16189
+ background: "repeating-conic-gradient(#B2B2B2 0% 25%, white 25% 50%) 50% / 32px 32px",
15809
16190
  },
15810
16191
  previewContainer: {
15811
16192
  display: "flex",
@@ -15813,8 +16194,6 @@ const useStyles$9 = makeStyles({
15813
16194
  marginTop: tokens.spacingVerticalXS,
15814
16195
  marginBottom: tokens.spacingVerticalS,
15815
16196
  width: "100%",
15816
- // Checkerboard background to show transparency
15817
- background: "repeating-conic-gradient(#B2B2B2 0% 25%, white 25% 50%) 50% / 32px 32px",
15818
16197
  },
15819
16198
  });
15820
16199
  // This method of holding TextureChannels was brought over from inspectorv1 and can likely be refactored/simplified
@@ -15834,6 +16213,9 @@ const TexturePreview = (props) => {
15834
16213
  const [canvasStyle, setCanvasStyle] = useState();
15835
16214
  const internalTexture = useProperty(texture, "_texture");
15836
16215
  const { size } = useContext(ToolContext);
16216
+ // Watch for pinned state changes - when portaled, the canvas needs to be redrawn
16217
+ const accordionCtx = useContext(AccordionContext);
16218
+ const isPinned = accordionCtx?.state.pinnedIds.some((id) => id.endsWith("\0TexturePreview")) ?? false;
15837
16219
  const updatePreviewAsync = useCallback(async () => {
15838
16220
  const canvas = canvasRef.current;
15839
16221
  if (!canvas) {
@@ -15842,16 +16224,19 @@ const TexturePreview = (props) => {
15842
16224
  try {
15843
16225
  await WhenTextureReadyAsync(texture); // Ensure texture is loaded before grabbing size
15844
16226
  const { width: textureWidth, height: textureHeight } = texture.getSize();
15845
- // Set canvas dimensions to the sub-region size
15846
- canvas.width = width ?? textureWidth;
15847
- canvas.height = height ?? textureHeight;
16227
+ // Calculate canvas dimensions
16228
+ const canvasWidth = width ?? textureWidth;
16229
+ const canvasHeight = height ?? textureHeight;
15848
16230
  // Calculate the width that corresponds to maxHeight while maintaining aspect ratio
15849
- const aspectRatio = canvas.width / canvas.height;
16231
+ const aspectRatio = canvasWidth / canvasHeight;
15850
16232
  // Use CSS min() to pick the smaller of maxWidth or the width that corresponds to maxHeight
15851
16233
  const imageWidth = `min(${maxWidth}, calc(${maxHeight} * ${aspectRatio}))`;
15852
16234
  setCanvasStyle({ width: imageWidth });
15853
- // Get full texture data, then draw only the sub-region
16235
+ // Fetch texture data BEFORE clearing the canvas to avoid flicker
15854
16236
  const data = await ApplyChannelsToTextureDataAsync(texture, textureWidth, textureHeight, face, channels);
16237
+ // Now set canvas dimensions (this clears the canvas) and draw immediately
16238
+ canvas.width = canvasWidth;
16239
+ canvas.height = canvasHeight;
15855
16240
  const context = canvas.getContext("2d");
15856
16241
  if (context) {
15857
16242
  const fullImageData = context.createImageData(textureWidth, textureHeight);
@@ -15868,9 +16253,13 @@ const TexturePreview = (props) => {
15868
16253
  useEffect(() => {
15869
16254
  void updatePreviewAsync();
15870
16255
  }, [updatePreviewAsync]);
15871
- return (jsxs("div", { className: classes.root, children: [disableToolbar ? null : texture.isCube ? (jsx(Toolbar$1, { className: classes.controls, size: size, "aria-label": "Cube Faces", children: ["+X", "-X", "+Y", "-Y", "+Z", "-Z"].map((label, idx) => (jsx(ToolbarButton, { className: classes.controlButton, appearance: face === idx ? "primary" : "subtle", onClick: () => setFace(idx), children: label }, label))) })) : (jsx(Toolbar$1, { className: classes.controls, size: size, "aria-label": "Channels", children: ["R", "G", "B", "A", "ALL"].map((ch) => (jsx(ToolbarButton, { className: classes.controlButton, appearance: channels === TextureChannelStates[ch] ? "primary" : "subtle", onClick: () => setChannels(TextureChannelStates[ch]), children: ch }, ch))) })), jsx("div", { className: classes.previewContainer, children: jsx("canvas", { ref: canvasRef, className: classes.preview, style: canvasStyle }) }), texture.isRenderTarget && (jsx(Button$1, { appearance: "outline", onClick: () => {
15872
- void updatePreviewAsync();
15873
- }, children: "Refresh" }))] }));
16256
+ // Redraw canvas after portaling (pinned state change moves DOM element, which can clear canvas)
16257
+ useEffect(() => {
16258
+ void updatePreviewAsync();
16259
+ }, [isPinned]);
16260
+ return (jsx(LineContainer, { uniqueId: "TexturePreview", children: jsxs("div", { className: classes.root, children: [disableToolbar ? null : texture.isCube ? (jsx(Toolbar$1, { className: classes.controls, size: size, "aria-label": "Cube Faces", children: ["+X", "-X", "+Y", "-Y", "+Z", "-Z"].map((label, idx) => (jsx(ToolbarButton, { className: classes.controlButton, appearance: face === idx ? "primary" : "subtle", onClick: () => setFace(idx), children: label }, label))) })) : (jsx(Toolbar$1, { className: classes.controls, size: size, "aria-label": "Channels", children: ["R", "G", "B", "A", "ALL"].map((ch) => (jsx(ToolbarButton, { className: classes.controlButton, appearance: channels === TextureChannelStates[ch] ? "primary" : "subtle", onClick: () => setChannels(TextureChannelStates[ch]), children: ch }, ch))) })), jsx("div", { className: classes.previewContainer, children: jsx("canvas", { ref: canvasRef, className: classes.preview, style: canvasStyle }) }), texture.isRenderTarget && (jsx(Button$1, { appearance: "outline", onClick: () => {
16261
+ void updatePreviewAsync();
16262
+ }, children: "Refresh" }))] }) }));
15874
16263
  };
15875
16264
 
15876
16265
  function useMaxCellCount(sprite) {
@@ -15899,7 +16288,7 @@ const SpriteAnimationProperties = (props) => {
15899
16288
  const { sprite } = props;
15900
16289
  const animationStarted = useObservableState(useCallback(() => sprite.animationStarted, [sprite]), useInterceptObservable("function", sprite, "playAnimation"), useInterceptObservable("function", sprite, "stopAnimation"), useInterceptObservable("function", sprite, "_animate"));
15901
16290
  const maxCellCount = useMaxCellCount(sprite);
15902
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Start", description: "First frame of the animation.", min: 0, max: maxCellCount, target: sprite, propertyKey: "fromIndex" }, "Start"), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "End", description: "Last frame of the animation.", min: 0, max: maxCellCount, target: sprite, propertyKey: "toIndex" }, "End"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Loop", description: "Whether to loop the animation.", target: sprite, propertyKey: "loopAnimation" }, "Loop"), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Delay", description: "Delay between frames in milliseconds.", min: 0, target: sprite, propertyKey: "delay" }, "Delay"), jsx(ButtonLine, { label: animationStarted ? "Stop Animation" : "Start Animation", icon: animationStarted ? StopFilled : PlayFilled, onClick: () => {
16291
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Start", description: "First frame of the animation.", min: 0, max: maxCellCount, target: sprite, propertyKey: "fromIndex" }, "Start"), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "End", description: "Last frame of the animation.", min: 0, max: maxCellCount, target: sprite, propertyKey: "toIndex" }, "End"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Loop", description: "Whether to loop the animation.", target: sprite, propertyKey: "loopAnimation" }, "Loop"), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Delay", description: "Delay between frames in milliseconds.", min: 0, target: sprite, propertyKey: "delay" }, "Delay"), jsx(ButtonLine, { uniqueId: "Start/Stop", label: animationStarted ? "Stop Animation" : "Start Animation", icon: animationStarted ? StopFilled : PlayFilled, onClick: () => {
15903
16292
  if (animationStarted) {
15904
16293
  sprite.stopAnimation();
15905
16294
  }
@@ -16153,7 +16542,7 @@ const BaseTextureTransformProperties = (props) => {
16153
16542
  const CubeTextureTransformProperties = (props) => {
16154
16543
  const { texture, settings } = props;
16155
16544
  const [toDisplayAngle, fromDisplayAngle] = useAngleConverters(settings);
16156
- return (jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Rotation Y", target: texture, propertyKey: "rotationY", min: 0, max: toDisplayAngle(Math.PI * 2), convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }));
16545
+ return (jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Rotation Y", target: texture, propertyKey: "rotationY", min: 0, max: toDisplayAngle(Math.PI * 2), step: 0.0001, convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }));
16157
16546
  };
16158
16547
 
16159
16548
  const MultiRenderTargetGeneralProperties = (props) => {
@@ -16185,7 +16574,7 @@ const TextureTransformProperties = (props) => {
16185
16574
  const [toDisplayAngle, fromDisplayAngle] = useAngleConverters(settings);
16186
16575
  const wrapU = useProperty(texture, "wrapU");
16187
16576
  const wrapV = useProperty(texture, "wrapV");
16188
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "U offset", target: texture, propertyKey: "uOffset", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "V offset", target: texture, propertyKey: "vOffset", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "U scale", target: texture, propertyKey: "uScale", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "V scale", target: texture, propertyKey: "vScale", step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "U angle", target: texture, propertyKey: "uAng", min: 0, max: toDisplayAngle(Math.PI * 2), convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "V angle", target: texture, propertyKey: "vAng", min: 0, max: toDisplayAngle(Math.PI * 2), convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "W angle", target: texture, propertyKey: "wAng", min: 0, max: toDisplayAngle(Math.PI * 2), convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(SwitchPropertyLine, { label: "Clamp U", value: wrapU === Constants.TEXTURE_CLAMP_ADDRESSMODE, onChange: (value) => (texture.wrapU = value ? Constants.TEXTURE_CLAMP_ADDRESSMODE : Constants.TEXTURE_WRAP_ADDRESSMODE) }), jsx(SwitchPropertyLine, { label: "Clamp V", value: wrapV === Constants.TEXTURE_CLAMP_ADDRESSMODE, onChange: (value) => (texture.wrapV = value ? Constants.TEXTURE_CLAMP_ADDRESSMODE : Constants.TEXTURE_WRAP_ADDRESSMODE) })] }));
16577
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "U offset", target: texture, propertyKey: "uOffset", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "V offset", target: texture, propertyKey: "vOffset", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "U scale", target: texture, propertyKey: "uScale", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "V scale", target: texture, propertyKey: "vScale", step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "U angle", target: texture, propertyKey: "uAng", min: 0, max: toDisplayAngle(Math.PI * 2), step: 0.01, convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "V angle", target: texture, propertyKey: "vAng", min: 0, max: toDisplayAngle(Math.PI * 2), step: 0.01, convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "W angle", target: texture, propertyKey: "wAng", min: 0, max: toDisplayAngle(Math.PI * 2), step: 0.01, convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(SwitchPropertyLine, { label: "Clamp U", value: wrapU === Constants.TEXTURE_CLAMP_ADDRESSMODE, onChange: (value) => (texture.wrapU = value ? Constants.TEXTURE_CLAMP_ADDRESSMODE : Constants.TEXTURE_WRAP_ADDRESSMODE) }), jsx(SwitchPropertyLine, { label: "Clamp V", value: wrapV === Constants.TEXTURE_CLAMP_ADDRESSMODE, onChange: (value) => (texture.wrapV = value ? Constants.TEXTURE_CLAMP_ADDRESSMODE : Constants.TEXTURE_WRAP_ADDRESSMODE) })] }));
16189
16578
  };
16190
16579
 
16191
16580
  const SamplingMode = [
@@ -16720,8 +17109,10 @@ class TextureCanvasManager {
16720
17109
  }
16721
17110
  async grabOriginalTexture() {
16722
17111
  // Grab image data from original texture and paint it onto the context of a DynamicTexture
16723
- this.setSize(this._originalTexture.getSize());
16724
- const data = await ApplyChannelsToTextureDataAsync(this._originalTexture, this._size.width, this._size.height, this._face, { R: true, G: true, B: true, A: true }, this._mipLevel);
17112
+ const size = this._originalTexture.getSize();
17113
+ // Fetch texture data BEFORE setting size (which clears the canvas) to avoid flicker
17114
+ const data = await ApplyChannelsToTextureDataAsync(this._originalTexture, size.width, size.height, this._face, { R: true, G: true, B: true, A: true }, this._mipLevel);
17115
+ this.setSize(size);
16725
17116
  this._imageData = data;
16726
17117
  this.paintPixelsOnCanvas(data, this._2DCanvas);
16727
17118
  this._3DCanvasTexture.update();
@@ -16817,6 +17208,7 @@ class TextureCanvasManager {
16817
17208
  this._onUpdate();
16818
17209
  }
16819
17210
  async resize(newSize) {
17211
+ // Fetch texture data BEFORE setting size (which clears the canvas) to avoid flicker
16820
17212
  const data = await ApplyChannelsToTextureDataAsync(this._originalTexture, newSize.width, newSize.height, this._face, { R: true, G: true, B: true, A: true });
16821
17213
  this.setSize(newSize);
16822
17214
  this.paintPixelsOnCanvas(data, this._2DCanvas);
@@ -19138,7 +19530,7 @@ const VideoCaptureTool = ({ scene }) => {
19138
19530
  void videoRecorder.startRecording(undefined, 0); // Use 0 to prevent automatic stop; let the user stop it
19139
19531
  setIsRecording(true);
19140
19532
  }, [scene]);
19141
- return (jsx(Fragment, { children: jsx(ButtonLine, { label: isRecording ? "Stop Recording" : "Record Video", icon: isRecording ? RecordStopRegular : RecordRegular, onClick: recordVideoAsync }) }));
19533
+ return (jsx(Fragment, { children: jsx(ButtonLine, { uniqueId: "Start/Stop", label: isRecording ? "Stop Recording" : "Record Video", icon: isRecording ? RecordStopRegular : RecordRegular, onClick: recordVideoAsync }) }));
19142
19534
  };
19143
19535
 
19144
19536
  const CaptureToolsDefinition = {
@@ -19194,6 +19586,8 @@ const EnvExportImageTypes = [
19194
19586
  { label: "WebP", value: 1, imageType: "image/webp" },
19195
19587
  ];
19196
19588
  const ExportBabylonTools = ({ scene }) => {
19589
+ // Track environment texture changes to re-render when it's updated (e.g., when a new HDRI is loaded)
19590
+ const environmentTexture = useProperty(scene, "environmentTexture");
19197
19591
  const [babylonExportOptions, setBabylonExportOptions] = useState({
19198
19592
  imageTypeIndex: 0,
19199
19593
  imageQuality: 0.8,
@@ -19205,11 +19599,11 @@ const ExportBabylonTools = ({ scene }) => {
19205
19599
  Tools.Download(blob, "scene.babylon");
19206
19600
  }, [scene]);
19207
19601
  const createEnvTexture = useCallback(async () => {
19208
- if (!scene.environmentTexture) {
19602
+ if (!environmentTexture) {
19209
19603
  return;
19210
19604
  }
19211
19605
  try {
19212
- const buffer = await EnvironmentTextureTools.CreateEnvTextureAsync(scene.environmentTexture, {
19606
+ const buffer = await EnvironmentTextureTools.CreateEnvTextureAsync(environmentTexture, {
19213
19607
  imageType: EnvExportImageTypes[babylonExportOptions.imageTypeIndex].imageType,
19214
19608
  imageQuality: babylonExportOptions.imageQuality,
19215
19609
  disableIrradianceTexture: !babylonExportOptions.iblDiffuse,
@@ -19221,8 +19615,8 @@ const ExportBabylonTools = ({ scene }) => {
19221
19615
  Logger.Error(error);
19222
19616
  alert(error);
19223
19617
  }
19224
- }, [scene, babylonExportOptions]);
19225
- return (jsxs(Fragment, { children: [jsx(ButtonLine, { label: "Export to Babylon", icon: ArrowDownloadRegular, onClick: exportBabylon }), !scene.getEngine().premultipliedAlpha && scene.environmentTexture && scene.environmentTexture._prefiltered && scene.activeCamera && (jsxs(Fragment, { children: [jsx(ButtonLine, { label: "Generate .env texture", icon: ArrowDownloadRegular, onClick: createEnvTexture }), scene.environmentTexture.irradianceTexture && (jsx(SwitchPropertyLine, { label: "Diffuse Texture", description: "Export diffuse texture for IBL", value: babylonExportOptions.iblDiffuse, onChange: (value) => {
19618
+ }, [scene, environmentTexture, babylonExportOptions]);
19619
+ return (jsxs(Fragment, { children: [jsx(ButtonLine, { label: "Export to Babylon", icon: ArrowDownloadRegular, onClick: exportBabylon }), !scene.getEngine().premultipliedAlpha && environmentTexture && environmentTexture._prefiltered && scene.activeCamera && (jsxs(Fragment, { children: [jsx(ButtonLine, { label: "Generate .env Texture", icon: ArrowDownloadRegular, onClick: createEnvTexture }), environmentTexture.irradianceTexture && (jsx(SwitchPropertyLine, { label: "Diffuse Texture", description: "Export diffuse texture for IBL", value: babylonExportOptions.iblDiffuse, onChange: (value) => {
19226
19620
  setBabylonExportOptions((prev) => ({ ...prev, iblDiffuse: value }));
19227
19621
  } }, "iblDiffuse")), jsx(NumberDropdownPropertyLine, { label: "Image type", options: EnvExportImageTypes, value: babylonExportOptions.imageTypeIndex, onChange: (val) => {
19228
19622
  setBabylonExportOptions((prev) => ({ ...prev, imageTypeIndex: val }));
@@ -20623,5 +21017,5 @@ const TextAreaPropertyLine = (props) => {
20623
21017
  // Attach Inspector v2 to Scene.debugLayer as a side effect for back compat.
20624
21018
  AttachDebugLayer();
20625
21019
 
20626
- export { useAngleConverters as $, Accordion as A, Button as B, CheckboxPropertyLine as C, DebugServiceIdentity as D, ExtensibleAccordion as E, useColor3Property as F, useColor4Property as G, useQuaternionProperty as H, Inspector as I, MakePropertyHook as J, useInterceptObservable as K, Link as L, MessageBar as M, NumberInputPropertyLine as N, useEventfulState as O, Popover as P, useObservableCollection as Q, useOrderedObservableCollection as R, SpinButtonPropertyLine as S, TextInputPropertyLine as T, usePollingObservable as U, Vector3PropertyLine as V, useResource as W, useAsyncResource as X, useCompactMode as Y, useDisableCopy as Z, useSidePaneDockOverrides as _, ShellServiceIdentity as a, MakeTeachingMoment as a0, MakeDialogTeachingMoment as a1, InterceptFunction as a2, GetPropertyDescriptor as a3, IsPropertyReadonly as a4, InterceptProperty as a5, ObservableCollection as a6, ConstructorFactory as a7, SelectionServiceIdentity as a8, SelectionServiceDefinition as a9, TextInput as aA, ToggleButton as aB, ChildWindow as aC, FileUploadLine as aD, FactorGradientList as aE, Color3GradientList as aF, Color4GradientList as aG, Pane as aH, BooleanBadgePropertyLine as aI, Color3PropertyLine as aJ, Color4PropertyLine as aK, HexPropertyLine as aL, LinkPropertyLine as aM, PropertyLine as aN, LineContainer as aO, PlaceholderPropertyLine as aP, StringifiedPropertyLine as aQ, SwitchPropertyLine as aR, SyncedSliderPropertyLine as aS, TextAreaPropertyLine as aT, TextPropertyLine as aU, RotationVectorPropertyLine as aV, QuaternionPropertyLine as aW, Vector2PropertyLine as aX, Vector4PropertyLine as aY, SettingsContextIdentity as aa, ShowInspector as ab, Checkbox as ac, Collapse as ad, ColorPickerPopup as ae, InputHexField as af, InputHsvField as ag, ComboBox as ah, DraggableLine as ai, Dropdown as aj, NumberDropdown as ak, StringDropdown as al, FactorGradientComponent as am, Color3GradientComponent as an, Color4GradientComponent as ao, ColorStepGradientComponent as ap, InfoLabel as aq, MakeLazyComponent as ar, List as as, PositionedPopover as at, SearchBar as au, SearchBox as av, SpinButton as aw, Switch as ax, SyncedSliderInput as ay, Textarea as az, SceneContextIdentity as b, useObservableState as c, AccordionSection as d, ButtonLine as e, ToolsServiceIdentity as f, useExtensionManager as g, MakePopoverTeachingMoment as h, TeachingMoment as i, SidePaneContainer as j, PropertiesServiceIdentity as k, SceneExplorerServiceIdentity as l, SettingsServiceIdentity as m, StatsServiceIdentity as n, ConvertOptions as o, AttachDebugLayer as p, DetachDebugLayer as q, NumberDropdownPropertyLine as r, StringDropdownPropertyLine as s, BoundProperty as t, useProperty as u, Property as v, LinkToEntityPropertyLine as w, Theme as x, BuiltInsExtensionFeed as y, useVector3Property as z };
20627
- //# sourceMappingURL=index-ByfjmUIP.js.map
21020
+ export { useAngleConverters as $, Accordion as A, Button as B, CheckboxPropertyLine as C, DebugServiceIdentity as D, ExtensibleAccordion as E, useColor3Property as F, useColor4Property as G, useQuaternionProperty as H, Inspector as I, MakePropertyHook as J, useInterceptObservable as K, Link as L, MessageBar as M, NumberInputPropertyLine as N, useEventfulState as O, Popover as P, useObservableCollection as Q, useOrderedObservableCollection as R, SpinButtonPropertyLine as S, TextInputPropertyLine as T, usePollingObservable as U, Vector3PropertyLine as V, useResource as W, useAsyncResource as X, useCompactMode as Y, useDisableCopy as Z, useSidePaneDockOverrides as _, ShellServiceIdentity as a, MakeTeachingMoment as a0, MakeDialogTeachingMoment as a1, InterceptFunction as a2, GetPropertyDescriptor as a3, IsPropertyReadonly as a4, InterceptProperty as a5, ObservableCollection as a6, ConstructorFactory as a7, SelectionServiceIdentity as a8, SelectionServiceDefinition as a9, Textarea as aA, TextInput as aB, ToggleButton as aC, ChildWindow as aD, FileUploadLine as aE, FactorGradientList as aF, Color3GradientList as aG, Color4GradientList as aH, Pane as aI, BooleanBadgePropertyLine as aJ, Color3PropertyLine as aK, Color4PropertyLine as aL, HexPropertyLine as aM, LinkPropertyLine as aN, PropertyLine as aO, LineContainer as aP, PlaceholderPropertyLine as aQ, StringifiedPropertyLine as aR, SwitchPropertyLine as aS, SyncedSliderPropertyLine as aT, TextAreaPropertyLine as aU, TextPropertyLine as aV, RotationVectorPropertyLine as aW, QuaternionPropertyLine as aX, Vector2PropertyLine as aY, Vector4PropertyLine as aZ, SettingsContextIdentity as aa, ShowInspector as ab, AccordionSectionItem as ac, Checkbox as ad, Collapse as ae, ColorPickerPopup as af, InputHexField as ag, InputHsvField as ah, ComboBox as ai, DraggableLine as aj, Dropdown as ak, NumberDropdown as al, StringDropdown as am, FactorGradientComponent as an, Color3GradientComponent as ao, Color4GradientComponent as ap, ColorStepGradientComponent as aq, InfoLabel as ar, MakeLazyComponent as as, List as at, PositionedPopover as au, SearchBar as av, SearchBox as aw, SpinButton as ax, Switch as ay, SyncedSliderInput as az, SceneContextIdentity as b, useObservableState as c, AccordionSection as d, ButtonLine as e, ToolsServiceIdentity as f, useExtensionManager as g, MakePopoverTeachingMoment as h, TeachingMoment as i, SidePaneContainer as j, PropertiesServiceIdentity as k, SceneExplorerServiceIdentity as l, SettingsServiceIdentity as m, StatsServiceIdentity as n, ConvertOptions as o, AttachDebugLayer as p, DetachDebugLayer as q, NumberDropdownPropertyLine as r, StringDropdownPropertyLine as s, BoundProperty as t, useProperty as u, Property as v, LinkToEntityPropertyLine as w, Theme as x, BuiltInsExtensionFeed as y, useVector3Property as z };
21021
+ //# sourceMappingURL=index-BVYxLK-p.js.map