@babylonjs/inspector 8.52.0 → 8.53.0
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.
- package/lib/{extensionsListService-qU9tqfBg.js → extensionsListService-CAOSDkIg.js} +12 -11
- package/lib/extensionsListService-CAOSDkIg.js.map +1 -0
- package/lib/{index-Cmd13UXt.js → index-Ddfh2kw4.js} +969 -689
- package/lib/index-Ddfh2kw4.js.map +1 -0
- package/lib/index.d.ts +2676 -2579
- package/lib/index.js +3 -3
- package/lib/{quickCreateToolsService-C9jZpIAl.js → quickCreateToolsService-DeZ7ZJOC.js} +6 -4
- package/lib/quickCreateToolsService-DeZ7ZJOC.js.map +1 -0
- package/lib/{reflectorService-DGy36OAK.js → reflectorService-DE0Ic3N5.js} +4 -4
- package/lib/{reflectorService-DGy36OAK.js.map → reflectorService-DE0Ic3N5.js.map} +1 -1
- package/package.json +1 -1
- package/lib/extensionsListService-qU9tqfBg.js.map +0 -1
- package/lib/index-Cmd13UXt.js.map +0 -1
- package/lib/quickCreateToolsService-C9jZpIAl.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
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, Link as Link$1, Caption1, Body1, useFluent, Accordion as Accordion$1, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, MessageBar as MessageBar$1, MessageBarBody, AccordionItem, SearchBox as SearchBox$1, Portal, ToggleButton as ToggleButton$1, InfoLabel as InfoLabel$1, mergeClasses, Body1Strong, useId, useToastController, Toast, ToastTitle, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Switch as Switch$1, createDOMRenderer, RendererProvider, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, treeItemLevelToken, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, MenuItemCheckbox,
|
|
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, SettingsRegular, DocumentTextRegular, createFluentIcon, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, ArrowUploadRegular, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, WeatherSunnyRegular, WeatherMoonRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, CameraRegular, 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, LightbulbRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, SoundWaveCircleRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, PersonFeedbackRegular, BranchRegular, DeleteFilled } from '@fluentui/react-icons';
|
|
3
|
+
import { tokens, makeStyles, Tooltip as Tooltip$1, Button as Button$1, Spinner, Link as Link$1, Caption1, Body1, useFluent, Accordion as Accordion$1, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, MessageBar as MessageBar$1, MessageBarBody, AccordionItem, SearchBox as SearchBox$1, Portal, ToggleButton as ToggleButton$1, InfoLabel as InfoLabel$1, mergeClasses, Body1Strong, useId, useToastController, Toast, ToastTitle, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Switch as Switch$1, createDOMRenderer, RendererProvider, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, treeItemLevelToken, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, MenuItemCheckbox, useMergedRefs, Input, Dropdown as Dropdown$1, Option, Popover as Popover$1, PopoverTrigger, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch, PresenceBadge, Slider as Slider$1, 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, SettingsRegular, DocumentTextRegular, createFluentIcon, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, ArrowUploadRegular, ArrowBidirectionalUpDownFilled, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, ArrowClockwiseRegular, WeatherSunnyRegular, WeatherMoonRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, CameraRegular, 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, 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';
|
|
@@ -37,7 +37,7 @@ import { PerformanceViewerCollector } from '@babylonjs/core/Misc/PerformanceView
|
|
|
37
37
|
import { AbstractEngine } from '@babylonjs/core/Engines/abstractEngine.js';
|
|
38
38
|
import { Bone } from '@babylonjs/core/Bones/bone.js';
|
|
39
39
|
import { Camera } from '@babylonjs/core/Cameras/camera.js';
|
|
40
|
-
import { FrameGraphUtils } from '@babylonjs/core/FrameGraph/frameGraphUtils.js';
|
|
40
|
+
import { FrameGraphUtils, FindMainCamera, FindMainObjectRenderer } from '@babylonjs/core/FrameGraph/frameGraphUtils.js';
|
|
41
41
|
import { CameraGizmo } from '@babylonjs/core/Gizmos/cameraGizmo.js';
|
|
42
42
|
import { GizmoManager } from '@babylonjs/core/Gizmos/gizmoManager.js';
|
|
43
43
|
import { LightGizmo } from '@babylonjs/core/Gizmos/lightGizmo.js';
|
|
@@ -45,6 +45,8 @@ import { Light } from '@babylonjs/core/Lights/light.js';
|
|
|
45
45
|
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh.js';
|
|
46
46
|
import { Node as Node$1 } from '@babylonjs/core/node.js';
|
|
47
47
|
import { createRoot } from 'react-dom/client';
|
|
48
|
+
import { SelectionOutlineLayer } from '@babylonjs/core/Layers/selectionOutlineLayer.js';
|
|
49
|
+
import { GaussianSplattingMesh } from '@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingMesh.js';
|
|
48
50
|
import { AnimationGroup, TargetedAnimation } from '@babylonjs/core/Animations/animationGroup.js';
|
|
49
51
|
import { Animation } from '@babylonjs/core/Animations/animation.js';
|
|
50
52
|
import { AnimationPropertiesOverride } from '@babylonjs/core/Animations/animationPropertiesOverride.js';
|
|
@@ -80,7 +82,6 @@ import { NodeMaterialBlockConnectionPointTypes } from '@babylonjs/core/Materials
|
|
|
80
82
|
import { FactorGradient, Color3Gradient, ColorGradient } from '@babylonjs/core/Misc/gradients.js';
|
|
81
83
|
import { ReadFile } from '@babylonjs/core/Misc/fileTools.js';
|
|
82
84
|
import { CubeTexture } from '@babylonjs/core/Materials/Textures/cubeTexture.js';
|
|
83
|
-
import { GaussianSplattingMesh } from '@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingMesh.js';
|
|
84
85
|
import { Mesh } from '@babylonjs/core/Meshes/mesh.js';
|
|
85
86
|
import { SkeletonViewer } from '@babylonjs/core/Debug/skeletonViewer.js';
|
|
86
87
|
import { VertexBuffer } from '@babylonjs/core/Meshes/buffer.js';
|
|
@@ -144,7 +145,6 @@ import { ImportAnimationsAsync, SceneLoader } from '@babylonjs/core/Loading/scen
|
|
|
144
145
|
import { FilesInput } from '@babylonjs/core/Misc/filesInput.js';
|
|
145
146
|
import { GLTFLoaderAnimationStartMode, GLTFLoaderCoordinateSystemMode, GLTFLoaderDefaultOptions } from '@babylonjs/loaders/glTF/glTFFileLoader.js';
|
|
146
147
|
import { GLTFValidation } from '@babylonjs/loaders/glTF/glTFValidation.js';
|
|
147
|
-
import { SelectionOutlineLayer } from '@babylonjs/core/Layers/selectionOutlineLayer.js';
|
|
148
148
|
import { EngineStore } from '@babylonjs/core/Engines/engineStore.js';
|
|
149
149
|
import { DebugLayer } from '@babylonjs/core/Debug/debugLayer.js';
|
|
150
150
|
import { Lazy } from '@babylonjs/core/Misc/lazy.js';
|
|
@@ -276,7 +276,7 @@ const Button = forwardRef((props, ref) => {
|
|
|
276
276
|
});
|
|
277
277
|
Button.displayName = "Button";
|
|
278
278
|
|
|
279
|
-
const useStyles$
|
|
279
|
+
const useStyles$U = makeStyles({
|
|
280
280
|
root: {
|
|
281
281
|
display: "flex",
|
|
282
282
|
flexDirection: "column",
|
|
@@ -357,7 +357,7 @@ class ErrorBoundary extends Component {
|
|
|
357
357
|
}
|
|
358
358
|
}
|
|
359
359
|
function ErrorFallback({ error, onRetry }) {
|
|
360
|
-
const styles = useStyles$
|
|
360
|
+
const styles = useStyles$U();
|
|
361
361
|
return (jsxs("div", { className: styles.root, children: [jsx(ErrorCircleRegular, { className: styles.icon }), jsx("div", { className: styles.title, children: "Something went wrong" }), jsx("div", { className: styles.message, children: "An error occurred in this component. You can try again or continue using other parts of the tool." }), jsx(Button, { label: "Try Again", appearance: "primary", onClick: onRetry }), error && jsx("div", { className: styles.details, children: error.message })] }));
|
|
362
362
|
}
|
|
363
363
|
|
|
@@ -369,82 +369,6 @@ function usePropertyChangedNotifier() {
|
|
|
369
369
|
}, [propertyContext]);
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
const InterceptorHooksMaps$1 = new WeakMap();
|
|
373
|
-
/** @internal */
|
|
374
|
-
function InterceptFunction(target, propertyKey, hooks) {
|
|
375
|
-
if (!hooks.afterCall) {
|
|
376
|
-
throw new Error("At least one hook must be provided.");
|
|
377
|
-
}
|
|
378
|
-
const originalFunction = Reflect.get(target, propertyKey, target);
|
|
379
|
-
if (typeof originalFunction !== "function") {
|
|
380
|
-
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not a function.`);
|
|
381
|
-
}
|
|
382
|
-
// Make sure the property is configurable and writable, otherwise it is immutable and cannot be intercepted.
|
|
383
|
-
const propertyDescriptor = Reflect.getOwnPropertyDescriptor(target, propertyKey);
|
|
384
|
-
if (propertyDescriptor) {
|
|
385
|
-
if (!propertyDescriptor.configurable) {
|
|
386
|
-
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not configurable.`);
|
|
387
|
-
}
|
|
388
|
-
if (propertyDescriptor.writable === false || (propertyDescriptor.writable === undefined && !propertyDescriptor.set)) {
|
|
389
|
-
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is readonly.`);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
// Get or create the hooks map for the target object.
|
|
393
|
-
let hooksMap = InterceptorHooksMaps$1.get(target);
|
|
394
|
-
if (!hooksMap) {
|
|
395
|
-
InterceptorHooksMaps$1.set(target, (hooksMap = new Map()));
|
|
396
|
-
}
|
|
397
|
-
// Get or create the hooks array for the property key.
|
|
398
|
-
let hooksForKey = hooksMap.get(propertyKey);
|
|
399
|
-
if (!hooksForKey) {
|
|
400
|
-
hooksMap.set(propertyKey, (hooksForKey = []));
|
|
401
|
-
if (
|
|
402
|
-
// Replace the function with a new one that calls the hooks in addition to the original function.
|
|
403
|
-
!Reflect.set(target, propertyKey, (...args) => {
|
|
404
|
-
const result = Reflect.apply(originalFunction, target, args);
|
|
405
|
-
for (const { afterCall } of hooksForKey) {
|
|
406
|
-
afterCall?.(...args);
|
|
407
|
-
}
|
|
408
|
-
return result;
|
|
409
|
-
})) {
|
|
410
|
-
throw new Error(`Failed to define new function "${propertyKey.toString()}" on object "${target}".`);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
hooksForKey.push(hooks);
|
|
414
|
-
let isDisposed = false;
|
|
415
|
-
return {
|
|
416
|
-
dispose: () => {
|
|
417
|
-
if (!isDisposed) {
|
|
418
|
-
// Remove the hooks from the hooks array for the property key.
|
|
419
|
-
hooksForKey.splice(hooksForKey.indexOf(hooks), 1);
|
|
420
|
-
// If there are no more hooks for the property key, remove the property from the hooks map.
|
|
421
|
-
if (hooksForKey.length === 0) {
|
|
422
|
-
hooksMap.delete(propertyKey);
|
|
423
|
-
// If there are no more hooks for the target object, remove the hooks map from the WeakMap.
|
|
424
|
-
if (hooksMap.size === 0) {
|
|
425
|
-
InterceptorHooksMaps$1.delete(target);
|
|
426
|
-
}
|
|
427
|
-
if (propertyDescriptor) {
|
|
428
|
-
// If we have a property descriptor, it means the property was defined directly on the target object,
|
|
429
|
-
// in which case we replaced it and the original property descriptor needs to be restored.
|
|
430
|
-
if (!Reflect.defineProperty(target, propertyKey, propertyDescriptor)) {
|
|
431
|
-
throw new Error(`Failed to restore original function "${propertyKey.toString()}" on object "${target}".`);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
// Otherwise, the property was inherited through the prototype chain, and so we can simply delete it from
|
|
436
|
-
// the target object to allow it to fall back to the prototype chain as it did originally.
|
|
437
|
-
if (!Reflect.deleteProperty(target, propertyKey)) {
|
|
438
|
-
throw new Error(`Failed to delete transient function "${propertyKey.toString()}" on object "${target}".`);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
isDisposed = true;
|
|
443
|
-
}
|
|
444
|
-
},
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
|
|
448
372
|
/**
|
|
449
373
|
* Gets the property descriptor for a property on an object, including inherited properties.
|
|
450
374
|
* @param target The object containing the property.
|
|
@@ -474,7 +398,7 @@ function IsPropertyReadonly(propertyDescriptor) {
|
|
|
474
398
|
// If the property is not writable, it is readonly.
|
|
475
399
|
return propertyDescriptor.writable === false || (propertyDescriptor.writable === undefined && !propertyDescriptor.set);
|
|
476
400
|
}
|
|
477
|
-
const InterceptorHooksMaps = new WeakMap();
|
|
401
|
+
const InterceptorHooksMaps$1 = new WeakMap();
|
|
478
402
|
/** @internal */
|
|
479
403
|
function InterceptProperty(target, propertyKey, hooks) {
|
|
480
404
|
// Find the property descriptor and note the owning object (might be inherited through the prototype chain).
|
|
@@ -505,9 +429,9 @@ function InterceptProperty(target, propertyKey, hooks) {
|
|
|
505
429
|
}
|
|
506
430
|
}
|
|
507
431
|
// Get or create the hooks map for the target object.
|
|
508
|
-
let hooksMap = InterceptorHooksMaps.get(target);
|
|
432
|
+
let hooksMap = InterceptorHooksMaps$1.get(target);
|
|
509
433
|
if (!hooksMap) {
|
|
510
|
-
InterceptorHooksMaps.set(target, (hooksMap = new Map()));
|
|
434
|
+
InterceptorHooksMaps$1.set(target, (hooksMap = new Map()));
|
|
511
435
|
}
|
|
512
436
|
// Get or create the hooks array for the property key.
|
|
513
437
|
let hooksForKey = hooksMap.get(propertyKey);
|
|
@@ -547,7 +471,7 @@ function InterceptProperty(target, propertyKey, hooks) {
|
|
|
547
471
|
hooksMap.delete(propertyKey);
|
|
548
472
|
// If there are no more hooks for the target object, remove the hooks map from the WeakMap.
|
|
549
473
|
if (hooksMap.size === 0) {
|
|
550
|
-
InterceptorHooksMaps.delete(target);
|
|
474
|
+
InterceptorHooksMaps$1.delete(target);
|
|
551
475
|
}
|
|
552
476
|
const shouldRestorePropertyDescriptor =
|
|
553
477
|
// If the property is owned by the target object, then we may have replaced an original property descriptor that needs to be restore.
|
|
@@ -573,6 +497,95 @@ function InterceptProperty(target, propertyKey, hooks) {
|
|
|
573
497
|
};
|
|
574
498
|
}
|
|
575
499
|
|
|
500
|
+
const DefaultWatcher = {
|
|
501
|
+
watchProperty(target, propertyKey, onChanged) {
|
|
502
|
+
return InterceptProperty(target, propertyKey, {
|
|
503
|
+
afterSet: (value) => onChanged(value),
|
|
504
|
+
});
|
|
505
|
+
},
|
|
506
|
+
refresh: () => { },
|
|
507
|
+
};
|
|
508
|
+
const WatcherContext = createContext(DefaultWatcher);
|
|
509
|
+
function useWatcher() {
|
|
510
|
+
return useContext(WatcherContext);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const InterceptorHooksMaps = new WeakMap();
|
|
514
|
+
/** @internal */
|
|
515
|
+
function InterceptFunction(target, propertyKey, hooks) {
|
|
516
|
+
if (!hooks.afterCall) {
|
|
517
|
+
throw new Error("At least one hook must be provided.");
|
|
518
|
+
}
|
|
519
|
+
const originalFunction = Reflect.get(target, propertyKey, target);
|
|
520
|
+
if (typeof originalFunction !== "function") {
|
|
521
|
+
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not a function.`);
|
|
522
|
+
}
|
|
523
|
+
// Make sure the property is configurable and writable, otherwise it is immutable and cannot be intercepted.
|
|
524
|
+
const propertyDescriptor = Reflect.getOwnPropertyDescriptor(target, propertyKey);
|
|
525
|
+
if (propertyDescriptor) {
|
|
526
|
+
if (!propertyDescriptor.configurable) {
|
|
527
|
+
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not configurable.`);
|
|
528
|
+
}
|
|
529
|
+
if (propertyDescriptor.writable === false || (propertyDescriptor.writable === undefined && !propertyDescriptor.set)) {
|
|
530
|
+
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is readonly.`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
// Get or create the hooks map for the target object.
|
|
534
|
+
let hooksMap = InterceptorHooksMaps.get(target);
|
|
535
|
+
if (!hooksMap) {
|
|
536
|
+
InterceptorHooksMaps.set(target, (hooksMap = new Map()));
|
|
537
|
+
}
|
|
538
|
+
// Get or create the hooks array for the property key.
|
|
539
|
+
let hooksForKey = hooksMap.get(propertyKey);
|
|
540
|
+
if (!hooksForKey) {
|
|
541
|
+
hooksMap.set(propertyKey, (hooksForKey = []));
|
|
542
|
+
if (
|
|
543
|
+
// Replace the function with a new one that calls the hooks in addition to the original function.
|
|
544
|
+
!Reflect.set(target, propertyKey, (...args) => {
|
|
545
|
+
const result = Reflect.apply(originalFunction, target, args);
|
|
546
|
+
for (const { afterCall } of hooksForKey) {
|
|
547
|
+
afterCall?.(...args);
|
|
548
|
+
}
|
|
549
|
+
return result;
|
|
550
|
+
})) {
|
|
551
|
+
throw new Error(`Failed to define new function "${propertyKey.toString()}" on object "${target}".`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
hooksForKey.push(hooks);
|
|
555
|
+
let isDisposed = false;
|
|
556
|
+
return {
|
|
557
|
+
dispose: () => {
|
|
558
|
+
if (!isDisposed) {
|
|
559
|
+
// Remove the hooks from the hooks array for the property key.
|
|
560
|
+
hooksForKey.splice(hooksForKey.indexOf(hooks), 1);
|
|
561
|
+
// If there are no more hooks for the property key, remove the property from the hooks map.
|
|
562
|
+
if (hooksForKey.length === 0) {
|
|
563
|
+
hooksMap.delete(propertyKey);
|
|
564
|
+
// If there are no more hooks for the target object, remove the hooks map from the WeakMap.
|
|
565
|
+
if (hooksMap.size === 0) {
|
|
566
|
+
InterceptorHooksMaps.delete(target);
|
|
567
|
+
}
|
|
568
|
+
if (propertyDescriptor) {
|
|
569
|
+
// If we have a property descriptor, it means the property was defined directly on the target object,
|
|
570
|
+
// in which case we replaced it and the original property descriptor needs to be restored.
|
|
571
|
+
if (!Reflect.defineProperty(target, propertyKey, propertyDescriptor)) {
|
|
572
|
+
throw new Error(`Failed to restore original function "${propertyKey.toString()}" on object "${target}".`);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
// Otherwise, the property was inherited through the prototype chain, and so we can simply delete it from
|
|
577
|
+
// the target object to allow it to fall back to the prototype chain as it did originally.
|
|
578
|
+
if (!Reflect.deleteProperty(target, propertyKey)) {
|
|
579
|
+
throw new Error(`Failed to delete transient function "${propertyKey.toString()}" on object "${target}".`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
isDisposed = true;
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
576
589
|
/**
|
|
577
590
|
* Provides an observable that fires when a specified function/property is called/set.
|
|
578
591
|
* @param type The type of the interceptor, either "function" or "property".
|
|
@@ -583,6 +596,7 @@ function InterceptProperty(target, propertyKey, hooks) {
|
|
|
583
596
|
function useInterceptObservable(type, target, propertyKey) {
|
|
584
597
|
// Create a cached observable. It effectively has the lifetime of the component that uses this hook.
|
|
585
598
|
const observable = useMemo(() => new Observable(), []);
|
|
599
|
+
const watcher = useWatcher();
|
|
586
600
|
// Whenever the type, target, or property key changes, we need to set up a new interceptor.
|
|
587
601
|
useEffect(() => {
|
|
588
602
|
let interceptToken = null;
|
|
@@ -595,11 +609,7 @@ function useInterceptObservable(type, target, propertyKey) {
|
|
|
595
609
|
});
|
|
596
610
|
}
|
|
597
611
|
else if (type === "property") {
|
|
598
|
-
interceptToken =
|
|
599
|
-
afterSet: () => {
|
|
600
|
-
observable.notifyObservers();
|
|
601
|
-
},
|
|
602
|
-
});
|
|
612
|
+
interceptToken = watcher.watchProperty(target, propertyKey, () => observable.notifyObservers());
|
|
603
613
|
}
|
|
604
614
|
else {
|
|
605
615
|
throw new Error(`Unknown interceptor type: ${type}`);
|
|
@@ -1068,14 +1078,20 @@ function useKeyState(key, options) {
|
|
|
1068
1078
|
useKeyListener({
|
|
1069
1079
|
onKeyDown: useCallback((e) => {
|
|
1070
1080
|
if (e.key === key) {
|
|
1081
|
+
if (options?.preventDefault) {
|
|
1082
|
+
e.preventDefault();
|
|
1083
|
+
}
|
|
1071
1084
|
setIsPressed(true);
|
|
1072
1085
|
}
|
|
1073
|
-
}, [key]),
|
|
1086
|
+
}, [key, options?.preventDefault]),
|
|
1074
1087
|
onKeyUp: useCallback((e) => {
|
|
1075
1088
|
if (e.key === key) {
|
|
1089
|
+
if (options?.preventDefault) {
|
|
1090
|
+
e.preventDefault();
|
|
1091
|
+
}
|
|
1076
1092
|
setIsPressed(false);
|
|
1077
1093
|
}
|
|
1078
|
-
}, [key]),
|
|
1094
|
+
}, [key, options?.preventDefault]),
|
|
1079
1095
|
}, options);
|
|
1080
1096
|
useEventListener("window", "blur", useCallback(() => setIsPressed(false), []), options); // Reset state on window blur to avoid stuck keys
|
|
1081
1097
|
return isPressed;
|
|
@@ -1338,7 +1354,7 @@ function useIsSectionEmpty(sectionId) {
|
|
|
1338
1354
|
return hasItems;
|
|
1339
1355
|
}
|
|
1340
1356
|
|
|
1341
|
-
const useStyles$
|
|
1357
|
+
const useStyles$T = makeStyles({
|
|
1342
1358
|
accordion: {
|
|
1343
1359
|
display: "flex",
|
|
1344
1360
|
flexDirection: "column",
|
|
@@ -1416,6 +1432,7 @@ const useStyles$S = makeStyles({
|
|
|
1416
1432
|
},
|
|
1417
1433
|
searchBox: {
|
|
1418
1434
|
width: "100%",
|
|
1435
|
+
maxWidth: "none",
|
|
1419
1436
|
},
|
|
1420
1437
|
});
|
|
1421
1438
|
/**
|
|
@@ -1425,19 +1442,19 @@ const useStyles$S = makeStyles({
|
|
|
1425
1442
|
*/
|
|
1426
1443
|
const AccordionMenuBar = () => {
|
|
1427
1444
|
AccordionMenuBar.displayName = "AccordionMenuBar";
|
|
1428
|
-
const classes = useStyles$
|
|
1445
|
+
const classes = useStyles$T();
|
|
1429
1446
|
const accordionCtx = useContext(AccordionContext);
|
|
1430
1447
|
if (!accordionCtx) {
|
|
1431
1448
|
return null;
|
|
1432
1449
|
}
|
|
1433
1450
|
const { state, dispatch, features } = accordionCtx;
|
|
1434
1451
|
const { editMode } = state;
|
|
1435
|
-
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: "
|
|
1452
|
+
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: "transparent", onClick: () => dispatch({ type: "SHOW_ALL" }) }), jsx(Button, { title: "Hide all", icon: EyeOffRegular, appearance: "transparent", onClick: () => {
|
|
1436
1453
|
// Hide all visible (non-hidden) items using the registered item IDs
|
|
1437
1454
|
const { registeredItemIds, state: currentState } = accordionCtx;
|
|
1438
1455
|
const visibleItemIds = Array.from(registeredItemIds.keys()).filter((id) => !currentState.hiddenIds.includes(id));
|
|
1439
1456
|
dispatch({ type: "HIDE_ALL_VISIBLE", visibleItemIds });
|
|
1440
|
-
} })] })), (features.pinning || features.hiding) && (jsx(Button, { title: "Edit mode", icon: editMode ? CheckmarkFilled : EditRegular, appearance: editMode ? "primary" : "
|
|
1457
|
+
} })] })), (features.pinning || features.hiding) && (jsx(Button, { title: "Edit mode", icon: editMode ? CheckmarkFilled : EditRegular, appearance: editMode ? "primary" : "transparent", onClick: () => dispatch({ type: "SET_EDIT_MODE", enabled: !editMode }) }))] })] }));
|
|
1441
1458
|
};
|
|
1442
1459
|
/**
|
|
1443
1460
|
* Wrapper component that must encapsulate the section headers and panels.
|
|
@@ -1468,7 +1485,7 @@ const AccordionSectionBlock = (props) => {
|
|
|
1468
1485
|
const AccordionSectionItem = (props) => {
|
|
1469
1486
|
AccordionSectionItem.displayName = "AccordionSectionItem";
|
|
1470
1487
|
const { children, staticItem } = props;
|
|
1471
|
-
const classes = useStyles$
|
|
1488
|
+
const classes = useStyles$T();
|
|
1472
1489
|
const accordionCtx = useContext(AccordionContext);
|
|
1473
1490
|
const itemState = useAccordionSectionItemState(props);
|
|
1474
1491
|
const [ctrlMode, setCtrlMode] = useState(false);
|
|
@@ -1508,7 +1525,7 @@ const AccordionSectionItem = (props) => {
|
|
|
1508
1525
|
*/
|
|
1509
1526
|
const AccordionPinnedContainer = () => {
|
|
1510
1527
|
AccordionPinnedContainer.displayName = "AccordionPinnedContainer";
|
|
1511
|
-
const classes = useStyles$
|
|
1528
|
+
const classes = useStyles$T();
|
|
1512
1529
|
const accordionCtx = useContext(AccordionContext);
|
|
1513
1530
|
return (jsx("div", { ref: accordionCtx?.pinnedContainerRef, className: classes.pinnedContainer, children: jsx(MessageBar$1, { className: classes.pinnedContainerEmpty, children: jsx(MessageBarBody, { children: "No pinned items" }) }) }));
|
|
1514
1531
|
};
|
|
@@ -1519,7 +1536,7 @@ const AccordionPinnedContainer = () => {
|
|
|
1519
1536
|
*/
|
|
1520
1537
|
const AccordionSearchBox = () => {
|
|
1521
1538
|
AccordionSearchBox.displayName = "AccordionSearchBox";
|
|
1522
|
-
const classes = useStyles$
|
|
1539
|
+
const classes = useStyles$T();
|
|
1523
1540
|
const accordionCtx = useContext(AccordionContext);
|
|
1524
1541
|
if (!accordionCtx?.features.search) {
|
|
1525
1542
|
return null;
|
|
@@ -1535,14 +1552,15 @@ const AccordionSearchBox = () => {
|
|
|
1535
1552
|
*/
|
|
1536
1553
|
const AccordionSection = (props) => {
|
|
1537
1554
|
AccordionSection.displayName = "AccordionSection";
|
|
1538
|
-
const classes = useStyles$
|
|
1555
|
+
const classes = useStyles$T();
|
|
1539
1556
|
return jsx("div", { className: classes.panelDiv, children: props.children });
|
|
1540
1557
|
};
|
|
1541
1558
|
const StringAccordion = Accordion$1;
|
|
1542
1559
|
const Accordion = forwardRef((props, ref) => {
|
|
1543
1560
|
Accordion.displayName = "Accordion";
|
|
1544
|
-
|
|
1545
|
-
const
|
|
1561
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1562
|
+
const { children, highlightSections, uniqueId, enablePinnedItems, enableHiddenItems, enableSearchItems, ...rest } = props;
|
|
1563
|
+
const classes = useStyles$T();
|
|
1546
1564
|
const { size } = useContext(ToolContext);
|
|
1547
1565
|
const accordionCtx = useAccordionContext(props);
|
|
1548
1566
|
const hasPinning = accordionCtx?.features.pinning ?? false;
|
|
@@ -1639,7 +1657,7 @@ const Collapse = (props) => {
|
|
|
1639
1657
|
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 }) }));
|
|
1640
1658
|
};
|
|
1641
1659
|
|
|
1642
|
-
const useStyles$
|
|
1660
|
+
const useStyles$S = makeStyles({
|
|
1643
1661
|
button: {
|
|
1644
1662
|
display: "flex",
|
|
1645
1663
|
alignItems: "center",
|
|
@@ -1657,7 +1675,7 @@ const ToggleButton = (props) => {
|
|
|
1657
1675
|
ToggleButton.displayName = "ToggleButton";
|
|
1658
1676
|
const { value, onChange, title, appearance = "subtle" } = props;
|
|
1659
1677
|
const { size } = useContext(ToolContext);
|
|
1660
|
-
const classes = useStyles$
|
|
1678
|
+
const classes = useStyles$S();
|
|
1661
1679
|
const [checked, setChecked] = useState(value);
|
|
1662
1680
|
const toggle = useCallback(() => {
|
|
1663
1681
|
setChecked((prevChecked) => {
|
|
@@ -1908,11 +1926,11 @@ const CompactModeSettingDescriptor = {
|
|
|
1908
1926
|
};
|
|
1909
1927
|
const UseDegreesSettingDescriptor = {
|
|
1910
1928
|
key: "UseDegrees",
|
|
1911
|
-
defaultValue:
|
|
1929
|
+
defaultValue: true,
|
|
1912
1930
|
};
|
|
1913
1931
|
const UseEulerSettingDescriptor = {
|
|
1914
1932
|
key: "UseEuler",
|
|
1915
|
-
defaultValue:
|
|
1933
|
+
defaultValue: true,
|
|
1916
1934
|
};
|
|
1917
1935
|
const DisableCopySettingDescriptor = {
|
|
1918
1936
|
key: "DisableCopy",
|
|
@@ -1996,7 +2014,7 @@ const UXContextProvider = (props) => {
|
|
|
1996
2014
|
function AsReadonlyArray(array) {
|
|
1997
2015
|
return array;
|
|
1998
2016
|
}
|
|
1999
|
-
const useStyles$
|
|
2017
|
+
const useStyles$R = makeStyles({
|
|
2000
2018
|
rootDiv: {
|
|
2001
2019
|
flex: 1,
|
|
2002
2020
|
overflow: "hidden",
|
|
@@ -2005,7 +2023,7 @@ const useStyles$Q = makeStyles({
|
|
|
2005
2023
|
},
|
|
2006
2024
|
});
|
|
2007
2025
|
function ExtensibleAccordion(props) {
|
|
2008
|
-
const classes = useStyles$
|
|
2026
|
+
const classes = useStyles$R();
|
|
2009
2027
|
const { children, sections, sectionContent, context, sectionsRef, ...rest } = props;
|
|
2010
2028
|
const defaultSections = useMemo(() => {
|
|
2011
2029
|
const defaultSections = [];
|
|
@@ -2130,7 +2148,7 @@ function ExtensibleAccordion(props) {
|
|
|
2130
2148
|
})] }) })) }));
|
|
2131
2149
|
}
|
|
2132
2150
|
|
|
2133
|
-
const useStyles$
|
|
2151
|
+
const useStyles$Q = makeStyles({
|
|
2134
2152
|
paneRootDiv: {
|
|
2135
2153
|
display: "flex",
|
|
2136
2154
|
flex: 1,
|
|
@@ -2143,7 +2161,7 @@ const useStyles$P = makeStyles({
|
|
|
2143
2161
|
*/
|
|
2144
2162
|
const SidePaneContainer = forwardRef((props, ref) => {
|
|
2145
2163
|
const { className, ...rest } = props;
|
|
2146
|
-
const classes = useStyles$
|
|
2164
|
+
const classes = useStyles$Q();
|
|
2147
2165
|
return (jsx("div", { className: mergeClasses(classes.paneRootDiv, className), ref: ref, ...rest, children: props.children }));
|
|
2148
2166
|
});
|
|
2149
2167
|
|
|
@@ -2393,7 +2411,7 @@ const Theme = (props) => {
|
|
|
2393
2411
|
return (jsx(FluentProvider, { theme: theme, applyStylesToPortals: applyStylesToPortals, ...rest, children: props.children }));
|
|
2394
2412
|
};
|
|
2395
2413
|
|
|
2396
|
-
const useStyles$
|
|
2414
|
+
const useStyles$P = makeStyles({
|
|
2397
2415
|
extensionTeachingPopover: {
|
|
2398
2416
|
maxWidth: "320px",
|
|
2399
2417
|
},
|
|
@@ -2404,7 +2422,7 @@ const useStyles$O = makeStyles({
|
|
|
2404
2422
|
* @returns The teaching moment popover.
|
|
2405
2423
|
*/
|
|
2406
2424
|
const TeachingMoment = ({ shouldDisplay, positioningRef, onOpenChange, title, description }) => {
|
|
2407
|
-
const classes = useStyles$
|
|
2425
|
+
const classes = useStyles$P();
|
|
2408
2426
|
return (jsx(TeachingPopover, { appearance: "brand", open: shouldDisplay, positioning: { positioningRef }, onOpenChange: onOpenChange, children: jsxs(TeachingPopoverSurface, { className: classes.extensionTeachingPopover, children: [jsx(TeachingPopoverHeader, { children: title }), jsx(TeachingPopoverBody, { children: description })] }) }));
|
|
2409
2427
|
};
|
|
2410
2428
|
|
|
@@ -2588,13 +2606,32 @@ function ConstructorFactory(constructor) {
|
|
|
2588
2606
|
return (...args) => new constructor(...args);
|
|
2589
2607
|
}
|
|
2590
2608
|
|
|
2591
|
-
|
|
2609
|
+
/**
|
|
2610
|
+
* A hook that provides a transient state value and a "pulse" function to set it.
|
|
2611
|
+
* The transient value is meant to be consumed immediately after being set, and will be cleared on the next render.
|
|
2612
|
+
* @typeParam T The type of the transient value.
|
|
2613
|
+
* @returns A tuple containing the transient value and a function to "pulse" the state.
|
|
2614
|
+
*/
|
|
2615
|
+
function useImpulse() {
|
|
2616
|
+
const impulseRef = useRef(undefined);
|
|
2617
|
+
const [, setVersion] = useState(0);
|
|
2618
|
+
const pulse = useCallback((value) => {
|
|
2619
|
+
impulseRef.current = value;
|
|
2620
|
+
setVersion((v) => v + 1);
|
|
2621
|
+
}, []);
|
|
2622
|
+
// Consume the impulse value and clear it
|
|
2623
|
+
const value = impulseRef.current;
|
|
2624
|
+
impulseRef.current = undefined;
|
|
2625
|
+
return [value, pulse];
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
const useStyles$O = makeStyles({
|
|
2592
2629
|
placeholderDiv: {
|
|
2593
2630
|
padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
|
|
2594
2631
|
},
|
|
2595
2632
|
});
|
|
2596
2633
|
const PropertiesPane = (props) => {
|
|
2597
|
-
const classes = useStyles$
|
|
2634
|
+
const classes = useStyles$O();
|
|
2598
2635
|
const entity = props.context;
|
|
2599
2636
|
return entity != null ? (jsx(ExtensibleAccordion, { ...props })) : (jsx("div", { className: classes.placeholderDiv, children: jsx(Body1Strong, { italic: true, children: "No entity selected." }) }));
|
|
2600
2637
|
};
|
|
@@ -2896,7 +2933,7 @@ const RightSidePaneHeightAdjustSettingDescriptor = {
|
|
|
2896
2933
|
};
|
|
2897
2934
|
const RootComponentServiceIdentity = Symbol("RootComponent");
|
|
2898
2935
|
const ShellServiceIdentity = Symbol("ShellService");
|
|
2899
|
-
const useStyles$
|
|
2936
|
+
const useStyles$N = makeStyles({
|
|
2900
2937
|
mainView: {
|
|
2901
2938
|
flex: 1,
|
|
2902
2939
|
display: "flex",
|
|
@@ -3099,34 +3136,38 @@ const DockMenu = (props) => {
|
|
|
3099
3136
|
};
|
|
3100
3137
|
const PaneHeader = (props) => {
|
|
3101
3138
|
const { id, title, dockOptions } = props;
|
|
3102
|
-
const classes = useStyles$
|
|
3139
|
+
const classes = useStyles$N();
|
|
3103
3140
|
return (jsxs("div", { className: classes.paneHeaderDiv, children: [jsx(Subtitle2Stronger, { className: classes.paneHeaderText, children: title }), jsx(DockMenu, { sidePaneId: id, dockOptions: dockOptions, children: jsx(Button$1, { className: classes.paneHeaderButton, appearance: "transparent", icon: jsx(MoreHorizontalRegular, {}) }) })] }));
|
|
3104
3141
|
};
|
|
3105
3142
|
// This is a wrapper for an item in a toolbar that simply adds a teaching moment, which is useful for dynamically added items, possibly from extensions.
|
|
3106
|
-
const ToolbarItem = (
|
|
3107
|
-
|
|
3143
|
+
const ToolbarItem = (props) => {
|
|
3144
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3145
|
+
const { verticalLocation, horizontalLocation, id, component: Component, displayName } = props;
|
|
3146
|
+
const classes = useStyles$N();
|
|
3108
3147
|
const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Bar/${verticalLocation}/${horizontalLocation}/${displayName ?? id}`), [displayName, id]);
|
|
3109
|
-
const teachingMoment = useTeachingMoment(
|
|
3110
|
-
|
|
3148
|
+
const teachingMoment = useTeachingMoment(props.teachingMoment === false);
|
|
3149
|
+
const title = typeof props.teachingMoment === "object" ? props.teachingMoment.title : (displayName ?? id);
|
|
3150
|
+
const description = typeof props.teachingMoment === "object" ? props.teachingMoment.description : `The "${displayName ?? id}" extension can be accessed here.`;
|
|
3151
|
+
return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay, title: title, description: description }), jsx("div", { className: classes.barItem, ref: teachingMoment.targetRef, children: jsx(Component, {}) })] }));
|
|
3111
3152
|
};
|
|
3112
3153
|
// TODO: Handle overflow, possibly via https://react.fluentui.dev/?path=/docs/components-overflow--docs with priority.
|
|
3113
3154
|
// This component just renders a toolbar with left aligned toolbar items on the left and right aligned toolbar items on the right.
|
|
3114
3155
|
const Toolbar = ({ location, components }) => {
|
|
3115
|
-
const classes = useStyles$
|
|
3156
|
+
const classes = useStyles$N();
|
|
3116
3157
|
const leftComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "left"), [components]);
|
|
3117
3158
|
const rightComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "right"), [components]);
|
|
3118
|
-
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,
|
|
3159
|
+
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, teachingMoment: entry.teachingMoment }, 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, teachingMoment: entry.teachingMoment }, entry.key))) })] })) }));
|
|
3119
3160
|
};
|
|
3120
3161
|
// 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.
|
|
3121
3162
|
const SidePaneTab = (props) => {
|
|
3122
3163
|
const { location, id, isSelected, isFirst, isLast, dockOptions,
|
|
3123
3164
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3124
|
-
icon: Icon, title,
|
|
3125
|
-
const classes = useStyles$
|
|
3165
|
+
icon: Icon, title, } = props;
|
|
3166
|
+
const classes = useStyles$N();
|
|
3126
3167
|
const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Pane/${location}/${title ?? id}`), [title, id]);
|
|
3127
|
-
const teachingMoment = useTeachingMoment(
|
|
3168
|
+
const teachingMoment = useTeachingMoment(props.teachingMoment === false);
|
|
3128
3169
|
const tabClass = mergeClasses(classes.tab, isSelected ? classes.selectedTab : classes.unselectedTab, isFirst ? classes.firstTab : undefined, isLast ? classes.lastTab : undefined);
|
|
3129
|
-
return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay
|
|
3170
|
+
return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay, title: typeof props.teachingMoment === "object" ? props.teachingMoment.title : (title ?? "Extension"), description: typeof props.teachingMoment === "object" ? props.teachingMoment.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: {
|
|
3130
3171
|
children: jsx(Icon, {}),
|
|
3131
3172
|
} }) }) }) })] }));
|
|
3132
3173
|
};
|
|
@@ -3134,7 +3175,7 @@ const SidePaneTab = (props) => {
|
|
|
3134
3175
|
// In "compact" mode, the tab list is integrated into the pane itself.
|
|
3135
3176
|
// In "full" mode, the returned tab list is later injected into the toolbar.
|
|
3136
3177
|
function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane, dockOperations, toolbarMode, topBarItems, bottomBarItems, initialCollapsed) {
|
|
3137
|
-
const classes = useStyles$
|
|
3178
|
+
const classes = useStyles$N();
|
|
3138
3179
|
const [topSelectedTab, setTopSelectedTab] = useState();
|
|
3139
3180
|
const [bottomSelectedTab, setBottomSelectedTab] = useState();
|
|
3140
3181
|
const [collapsed, setCollapsed] = useState(initialCollapsed);
|
|
@@ -3236,7 +3277,7 @@ function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane,
|
|
|
3236
3277
|
setCollapsed(false);
|
|
3237
3278
|
}, children: paneComponents.map((entry, index) => {
|
|
3238
3279
|
const isSelected = selectedTab?.key === entry.key;
|
|
3239
|
-
return (jsx(SidePaneTab, { location: location, id: entry.key, title: entry.title, icon: entry.icon,
|
|
3280
|
+
return (jsx(SidePaneTab, { location: location, id: entry.key, title: entry.title, icon: entry.icon, teachingMoment: entry.teachingMoment, isSelected: isSelected && !collapsed, isFirst: index === 0, isLast: index === paneComponents.length - 1, dockOptions: dockOptions }, entry.key));
|
|
3240
3281
|
}) }) })), toolbarMode === "full" && (jsx(Collapse, { visible: !isChildWindowOpen, orientation: "horizontal", children: expandCollapseButton }))] })) }));
|
|
3241
3282
|
}, [location, collapsed, isChildWindowOpen, expandCollapseButton]);
|
|
3242
3283
|
// 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).
|
|
@@ -3331,7 +3372,7 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
|
|
|
3331
3372
|
expand: () => onCollapseChanged.notifyObservers({ location: "right", collapsed: false }),
|
|
3332
3373
|
};
|
|
3333
3374
|
const rootComponent = () => {
|
|
3334
|
-
const classes = useStyles$
|
|
3375
|
+
const classes = useStyles$N();
|
|
3335
3376
|
const [sidePaneDockOverrides, setSidePaneDockOverrides] = useSetting(SidePaneDockOverridesSettingDescriptor);
|
|
3336
3377
|
// This function returns a promise that resolves after the dock change takes effect so that
|
|
3337
3378
|
// we can then select the re-docked pane.
|
|
@@ -3566,7 +3607,7 @@ const SettingsServiceDefinition = {
|
|
|
3566
3607
|
horizontalLocation: "right",
|
|
3567
3608
|
verticalLocation: "top",
|
|
3568
3609
|
order: 500,
|
|
3569
|
-
|
|
3610
|
+
teachingMoment: false,
|
|
3570
3611
|
content: () => {
|
|
3571
3612
|
const sections = useOrderedObservableCollection(sectionsCollection);
|
|
3572
3613
|
const sectionContent = useObservableCollection(sectionContentCollection);
|
|
@@ -3664,7 +3705,7 @@ const PropertiesServiceDefinition = {
|
|
|
3664
3705
|
const sectionsCollection = new ObservableCollection();
|
|
3665
3706
|
const sectionContentCollection = new ObservableCollection();
|
|
3666
3707
|
const onPropertyChanged = new Observable();
|
|
3667
|
-
const onHighlightSectionsRequested = new Observable();
|
|
3708
|
+
const onHighlightSectionsRequested = new Observable(undefined, true);
|
|
3668
3709
|
const registration = shellService.addSidePane({
|
|
3669
3710
|
key: "Properties",
|
|
3670
3711
|
title: "Properties",
|
|
@@ -3672,7 +3713,7 @@ const PropertiesServiceDefinition = {
|
|
|
3672
3713
|
horizontalLocation: "right",
|
|
3673
3714
|
verticalLocation: "top",
|
|
3674
3715
|
order: 100,
|
|
3675
|
-
|
|
3716
|
+
teachingMoment: false,
|
|
3676
3717
|
keepMounted: true,
|
|
3677
3718
|
content: () => {
|
|
3678
3719
|
const sections = useOrderedObservableCollection(sectionsCollection);
|
|
@@ -3696,15 +3737,23 @@ const PropertiesServiceDefinition = {
|
|
|
3696
3737
|
// The selected entity may be set at the same time as a highlight is requested.
|
|
3697
3738
|
// To account for this, we need to wait for one React render to complete before
|
|
3698
3739
|
// requesting the section highlight.
|
|
3699
|
-
const [pendingHighlight,
|
|
3740
|
+
const [pendingHighlight, pulsePendingHighlightSections] = useImpulse();
|
|
3700
3741
|
useEffect(() => {
|
|
3701
|
-
const observer = onHighlightSectionsRequested.add(
|
|
3702
|
-
|
|
3742
|
+
const observer = onHighlightSectionsRequested.add((sectionIds) => {
|
|
3743
|
+
// Now this UI component is observing, so we don't need to cache pending requests anymore.
|
|
3744
|
+
onHighlightSectionsRequested.notifyIfTriggered = false;
|
|
3745
|
+
onHighlightSectionsRequested.cleanLastNotifiedState();
|
|
3746
|
+
pulsePendingHighlightSections(sectionIds);
|
|
3747
|
+
});
|
|
3748
|
+
return () => {
|
|
3749
|
+
observer.remove();
|
|
3750
|
+
// Now this UI component is no longer observing, so we need to cache pending requests again.
|
|
3751
|
+
onHighlightSectionsRequested.notifyIfTriggered = true;
|
|
3752
|
+
};
|
|
3703
3753
|
}, []);
|
|
3704
3754
|
useEffect(() => {
|
|
3705
3755
|
if (pendingHighlight && sectionsRef.current) {
|
|
3706
3756
|
sectionsRef.current.highlightSections(pendingHighlight);
|
|
3707
|
-
setPendingHighlight(undefined);
|
|
3708
3757
|
}
|
|
3709
3758
|
}, [pendingHighlight]);
|
|
3710
3759
|
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 }) }));
|
|
@@ -4076,7 +4125,7 @@ function CoerceEntityArray(entities, sort) {
|
|
|
4076
4125
|
}
|
|
4077
4126
|
return entities;
|
|
4078
4127
|
}
|
|
4079
|
-
const useStyles$
|
|
4128
|
+
const useStyles$M = makeStyles({
|
|
4080
4129
|
rootDiv: {
|
|
4081
4130
|
flex: 1,
|
|
4082
4131
|
overflow: "hidden",
|
|
@@ -4092,6 +4141,7 @@ const useStyles$L = makeStyles({
|
|
|
4092
4141
|
searchBox: {
|
|
4093
4142
|
flex: 1,
|
|
4094
4143
|
padding: 0,
|
|
4144
|
+
maxWidth: "none",
|
|
4095
4145
|
},
|
|
4096
4146
|
tree: {
|
|
4097
4147
|
rowGap: 0,
|
|
@@ -4184,14 +4234,14 @@ function MakeInlineCommandElement(command, isPlaceholder) {
|
|
|
4184
4234
|
}
|
|
4185
4235
|
const SceneTreeItem = (props) => {
|
|
4186
4236
|
const { isSelected, select } = props;
|
|
4187
|
-
const classes = useStyles$
|
|
4237
|
+
const classes = useStyles$M();
|
|
4188
4238
|
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
4189
4239
|
const treeItemLayoutClass = mergeClasses(classes.sceneTreeItemLayout, compactMode ? classes.treeItemLayoutCompact : undefined);
|
|
4190
4240
|
return (jsx(FlatTreeItem, { className: classes.treeItem, value: "scene", itemType: "leaf", parentValue: undefined, "aria-level": 1, "aria-setsize": 1, "aria-posinset": 1, onClick: select, children: jsx(TreeItemLayout, { iconBefore: jsx(GlobeRegular, {}), className: treeItemLayoutClass, style: isSelected ? { backgroundColor: tokens.colorNeutralBackground1Selected } : undefined, children: jsx(Body1Strong, { wrap: false, truncate: true, children: "Scene" }) }) }, "scene"));
|
|
4191
4241
|
};
|
|
4192
4242
|
const SectionTreeItem = (props) => {
|
|
4193
4243
|
const { section, isFiltering, commandProviders, expandAll, collapseAll, isDropTarget, ...dropProps } = props;
|
|
4194
|
-
const classes = useStyles$
|
|
4244
|
+
const classes = useStyles$M();
|
|
4195
4245
|
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
4196
4246
|
// Get the commands that apply to this section.
|
|
4197
4247
|
const commands = useResource(useCallback(() => {
|
|
@@ -4208,7 +4258,7 @@ const SectionTreeItem = (props) => {
|
|
|
4208
4258
|
};
|
|
4209
4259
|
const EntityTreeItem = (props) => {
|
|
4210
4260
|
const { entityItem, isSelected, select, isFiltering, commandProviders, expandAll, collapseAll, isDragging, isDropTarget, ...dragProps } = props;
|
|
4211
|
-
const classes = useStyles$
|
|
4261
|
+
const classes = useStyles$M();
|
|
4212
4262
|
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
4213
4263
|
const hasChildren = !!entityItem.children?.length;
|
|
4214
4264
|
const displayInfo = useResource(useCallback(() => {
|
|
@@ -4324,7 +4374,7 @@ const EntityTreeItem = (props) => {
|
|
|
4324
4374
|
}, children: jsx(Body1, { wrap: false, truncate: true, children: name }) }) }, GetEntityId(entityItem.entity)) }), jsx(MenuPopover, { hidden: !hasChildren && contextMenuCommands.length === 0, children: jsxs(MenuList, { children: [hasChildren && (jsxs(Fragment, { children: [jsx(MenuItem, { icon: jsx(ArrowExpandAllRegular, {}), onClick: expandAll, children: jsx(Body1, { children: "Expand All" }) }), jsx(MenuItem, { icon: jsx(ArrowCollapseAllRegular, {}), onClick: collapseAll, children: jsx(Body1, { children: "Collapse All" }) })] })), hasChildren && contextMenuCommands.length > 0 && jsx(MenuDivider, {}), contextMenuItems] }) })] }));
|
|
4325
4375
|
};
|
|
4326
4376
|
const SceneExplorer = (props) => {
|
|
4327
|
-
const classes = useStyles$
|
|
4377
|
+
const classes = useStyles$M();
|
|
4328
4378
|
const { sections, entityCommandProviders, sectionCommandProviders, scene, selectedEntity = null } = props;
|
|
4329
4379
|
const [openItems, setOpenItems] = useState(new Set());
|
|
4330
4380
|
const [sceneVersion, setSceneVersion] = useState(0);
|
|
@@ -4617,7 +4667,7 @@ const SceneExplorerServiceDefinition = {
|
|
|
4617
4667
|
icon: CubeTreeRegular,
|
|
4618
4668
|
horizontalLocation: "left",
|
|
4619
4669
|
verticalLocation: "top",
|
|
4620
|
-
|
|
4670
|
+
teachingMoment: false,
|
|
4621
4671
|
keepMounted: true,
|
|
4622
4672
|
content: () => {
|
|
4623
4673
|
const sections = useOrderedObservableCollection(sectionsCollection);
|
|
@@ -4778,7 +4828,7 @@ const DebugServiceDefinition = {
|
|
|
4778
4828
|
horizontalLocation: "right",
|
|
4779
4829
|
verticalLocation: "top",
|
|
4780
4830
|
order: 200,
|
|
4781
|
-
|
|
4831
|
+
teachingMoment: false,
|
|
4782
4832
|
content: () => {
|
|
4783
4833
|
const sections = useOrderedObservableCollection(sectionsCollection);
|
|
4784
4834
|
const sectionContent = useObservableCollection(sectionContentCollection);
|
|
@@ -4901,7 +4951,7 @@ const UploadButton = (props) => {
|
|
|
4901
4951
|
*/
|
|
4902
4952
|
const FileUploadLine = ({ onClick, label, accept, ...buttonProps }) => {
|
|
4903
4953
|
FileUploadLine.displayName = "FileUploadLine";
|
|
4904
|
-
return (jsx(LineContainer, { uniqueId: label, children: jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
|
|
4954
|
+
return (jsx(LineContainer, { uniqueId: `${label}_upload`, label: label, children: jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
|
|
4905
4955
|
};
|
|
4906
4956
|
|
|
4907
4957
|
/**
|
|
@@ -5947,7 +5997,7 @@ class CanvasGraphService {
|
|
|
5947
5997
|
}
|
|
5948
5998
|
}
|
|
5949
5999
|
|
|
5950
|
-
const useStyles$
|
|
6000
|
+
const useStyles$L = makeStyles({
|
|
5951
6001
|
canvas: {
|
|
5952
6002
|
flexGrow: 1,
|
|
5953
6003
|
width: "100%",
|
|
@@ -5956,7 +6006,7 @@ const useStyles$K = makeStyles({
|
|
|
5956
6006
|
});
|
|
5957
6007
|
const CanvasGraph = (props) => {
|
|
5958
6008
|
const { collector, scene, layoutObservable, returnToPlayheadObservable, onVisibleRangeChangedObservable, initialGraphSize } = props;
|
|
5959
|
-
const classes = useStyles$
|
|
6009
|
+
const classes = useStyles$L();
|
|
5960
6010
|
const canvasRef = useRef(null);
|
|
5961
6011
|
useEffect(() => {
|
|
5962
6012
|
if (!canvasRef.current) {
|
|
@@ -6010,135 +6060,208 @@ const CanvasGraph = (props) => {
|
|
|
6010
6060
|
return jsx("canvas", { className: classes.canvas, ref: canvasRef });
|
|
6011
6061
|
};
|
|
6012
6062
|
|
|
6013
|
-
function CoerceStepValue(step,
|
|
6014
|
-
// When the
|
|
6015
|
-
if (
|
|
6063
|
+
function CoerceStepValue(step, isFineKeyPressed, isCourseKeyPressed) {
|
|
6064
|
+
// When the fine key is pressed, decrease step by a factor of 10.
|
|
6065
|
+
if (isFineKeyPressed) {
|
|
6016
6066
|
return step * 0.1;
|
|
6017
6067
|
}
|
|
6018
|
-
// When the
|
|
6019
|
-
if (
|
|
6068
|
+
// When the course key is pressed, increase step by a factor of 10.
|
|
6069
|
+
if (isCourseKeyPressed) {
|
|
6020
6070
|
return step * 10;
|
|
6021
6071
|
}
|
|
6022
6072
|
return step;
|
|
6023
6073
|
}
|
|
6074
|
+
// Allow arbitrary expressions, primarily for math operations (e.g. 10*60 for 10 minutes in seconds).
|
|
6075
|
+
// Use Function constructor to safely evaluate the expression without allowing access to scope.
|
|
6076
|
+
// If the expression is invalid, fallback to NaN which will be caught by validateValue and prevent committing.
|
|
6077
|
+
function EvaluateExpression(rawValue) {
|
|
6078
|
+
const val = rawValue.trim();
|
|
6079
|
+
try {
|
|
6080
|
+
return Number(Function(`"use strict";return (${val})`)());
|
|
6081
|
+
}
|
|
6082
|
+
catch {
|
|
6083
|
+
return NaN;
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
const useStyles$K = makeStyles({
|
|
6087
|
+
icon: {
|
|
6088
|
+
"&:hover": {
|
|
6089
|
+
color: tokens.colorBrandForeground1,
|
|
6090
|
+
},
|
|
6091
|
+
},
|
|
6092
|
+
});
|
|
6093
|
+
/**
|
|
6094
|
+
* A numeric input with a vertical drag-to-scrub icon (ArrowsBidirectionalRegular rotated 90°).
|
|
6095
|
+
* Click-and-drag up/down on the icon to increment/decrement the value.
|
|
6096
|
+
*/
|
|
6024
6097
|
const SpinButton = forwardRef((props, ref) => {
|
|
6025
|
-
SpinButton.displayName = "
|
|
6026
|
-
const
|
|
6098
|
+
SpinButton.displayName = "SpinButton2";
|
|
6099
|
+
const inputClasses = useInputStyles$1();
|
|
6100
|
+
const classes = useStyles$K();
|
|
6027
6101
|
const { size } = useContext(ToolContext);
|
|
6028
6102
|
const { min, max } = props;
|
|
6029
|
-
const
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
const
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
const
|
|
6036
|
-
const
|
|
6037
|
-
// step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin
|
|
6038
|
-
const step = CoerceStepValue(props.step ?? 1, isUnfocusedAltKeyPressed || isFocusedAltKeyPressed, isUnfocusedShiftKeyPressed || isFocusedShiftKeyPressed);
|
|
6103
|
+
const baseStep = props.step ?? 1;
|
|
6104
|
+
// Local ref for the input element so we can blur it programmatically (e.g. when a drag starts while editing).
|
|
6105
|
+
const inputRef = useRef(null);
|
|
6106
|
+
const mergedRef = useMergedRefs(ref, inputRef);
|
|
6107
|
+
// Modifier keys for step coercion.
|
|
6108
|
+
const isAltKeyPressed = useKeyState("Alt", { preventDefault: true });
|
|
6109
|
+
const isShiftKeyPressed = useKeyState("Shift");
|
|
6110
|
+
const step = CoerceStepValue(baseStep, isAltKeyPressed, isShiftKeyPressed);
|
|
6039
6111
|
const stepPrecision = Math.max(0, CalculatePrecision(step));
|
|
6112
|
+
const [value, setValue] = useState(props.value ?? 0);
|
|
6113
|
+
const lastCommittedValue = useRef(props.value);
|
|
6114
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
6115
|
+
const scrubStartYRef = useRef(0);
|
|
6116
|
+
const scrubStartValueRef = useRef(0);
|
|
6117
|
+
const lastPointerYRef = useRef(0);
|
|
6118
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
6119
|
+
// Editing state: when the user is typing, we show their raw text rather than the formatted value.
|
|
6120
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
6121
|
+
const [editText, setEditText] = useState("");
|
|
6040
6122
|
const valuePrecision = Math.max(0, CalculatePrecision(value));
|
|
6041
|
-
// Display precision: controls how many decimals are shown in the formatted displayValue. Cap at 4 to avoid wild numbers
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
//
|
|
6045
|
-
const
|
|
6123
|
+
// Display precision: controls how many decimals are shown in the formatted displayValue. Cap at 4 to avoid wild numbers.
|
|
6124
|
+
// If a fixed precision prop is provided, use it instead.
|
|
6125
|
+
const displayPrecision = props.precision ?? Math.min(4, Math.max(stepPrecision, valuePrecision));
|
|
6126
|
+
// Format a number for display: toFixed, then trim trailing zeros and period unless a fixed precision is specified.
|
|
6127
|
+
const formatValue = useCallback((v) => {
|
|
6128
|
+
const fixed = v.toFixed(displayPrecision);
|
|
6129
|
+
if (props.precision !== undefined) {
|
|
6130
|
+
return fixed;
|
|
6131
|
+
}
|
|
6132
|
+
return fixed.replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "");
|
|
6133
|
+
}, [displayPrecision, props.precision]);
|
|
6046
6134
|
useEffect(() => {
|
|
6047
|
-
if (props.value !== lastCommittedValue.current) {
|
|
6135
|
+
if (!isDragging && props.value !== lastCommittedValue.current) {
|
|
6048
6136
|
lastCommittedValue.current = props.value;
|
|
6049
|
-
setValue(props.value);
|
|
6137
|
+
setValue(props.value ?? 0);
|
|
6050
6138
|
}
|
|
6051
|
-
}, [props.value]);
|
|
6052
|
-
const validateValue = (numericValue) => {
|
|
6139
|
+
}, [props.value, isDragging]);
|
|
6140
|
+
const validateValue = useCallback((numericValue) => {
|
|
6053
6141
|
const outOfBounds = (min !== undefined && numericValue < min) || (max !== undefined && numericValue > max);
|
|
6054
6142
|
const failsValidator = props.validator && !props.validator(numericValue);
|
|
6055
6143
|
const failsIntCheck = props.forceInt ? !Number.isInteger(numericValue) : false;
|
|
6056
6144
|
const invalid = !!outOfBounds || !!failsValidator || isNaN(numericValue) || !!failsIntCheck;
|
|
6057
6145
|
return !invalid;
|
|
6058
|
-
};
|
|
6059
|
-
|
|
6060
|
-
|
|
6146
|
+
}, [min, max, props.validator, props.forceInt]);
|
|
6147
|
+
// Constrain a value to the valid range by clamping to [min, max].
|
|
6148
|
+
const constrainValue = useCallback((v) => Clamp(v, min ?? -Infinity, max ?? Infinity), [min, max]);
|
|
6149
|
+
const tryCommitValue = useCallback((currVal) => {
|
|
6061
6150
|
if (validateValue(currVal) && currVal !== lastCommittedValue.current) {
|
|
6062
6151
|
lastCommittedValue.current = currVal;
|
|
6063
6152
|
props.onChange(currVal);
|
|
6064
6153
|
}
|
|
6065
|
-
};
|
|
6066
|
-
const
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
const regex = new RegExp("\\s*" + props.unit + "$");
|
|
6079
|
-
const match = val.match(regex);
|
|
6080
|
-
if (match) {
|
|
6081
|
-
return val.slice(0, -match[0].length);
|
|
6082
|
-
}
|
|
6083
|
-
return val;
|
|
6084
|
-
};
|
|
6085
|
-
// Allow arbitrary expressions, primarily for math operations (e.g. 10*60 for 10 minutes in seconds).
|
|
6086
|
-
// Use Function constructor to safely evaluate the expression without allowing access to scope.
|
|
6087
|
-
// If the expression is invalid, fallback to NaN which will be caught by validateValue and prevent committing.
|
|
6088
|
-
const evaluateExpression = (rawValue) => {
|
|
6089
|
-
const val = stripUnit(rawValue).trim();
|
|
6090
|
-
try {
|
|
6091
|
-
return Number(Function(`"use strict";return (${val})`)());
|
|
6092
|
-
}
|
|
6093
|
-
catch {
|
|
6094
|
-
return NaN;
|
|
6154
|
+
}, [validateValue, props.onChange]);
|
|
6155
|
+
const handleInputChange = useCallback((_, data) => {
|
|
6156
|
+
// Just update the raw text — no evaluation or commit until Enter/blur.
|
|
6157
|
+
setEditText(data.value);
|
|
6158
|
+
}, []);
|
|
6159
|
+
// Evaluate the current edit text and commit the value. Returns the clamped value if valid, or undefined.
|
|
6160
|
+
const commitEditText = useCallback((text) => {
|
|
6161
|
+
const numericValue = EvaluateExpression(text);
|
|
6162
|
+
if (!isNaN(numericValue) && validateValue(numericValue)) {
|
|
6163
|
+
const constrained = constrainValue(numericValue);
|
|
6164
|
+
setValue(constrained);
|
|
6165
|
+
tryCommitValue(constrained);
|
|
6166
|
+
return constrained;
|
|
6095
6167
|
}
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6168
|
+
return undefined;
|
|
6169
|
+
}, [validateValue, constrainValue, tryCommitValue]);
|
|
6170
|
+
const handleIconPointerDown = useCallback((e) => {
|
|
6171
|
+
e.preventDefault();
|
|
6172
|
+
e.stopPropagation();
|
|
6173
|
+
// If the input was being edited, commit the current text and blur the input
|
|
6174
|
+
// so the focus state stays consistent after the drag ends.
|
|
6175
|
+
let startValue = value;
|
|
6176
|
+
if (isEditing) {
|
|
6177
|
+
const committed = commitEditText(editText);
|
|
6178
|
+
if (committed !== undefined) {
|
|
6179
|
+
startValue = committed;
|
|
6180
|
+
}
|
|
6181
|
+
setIsEditing(false);
|
|
6182
|
+
}
|
|
6183
|
+
// Blur the active element to ensure we can observe document level modifier keys.
|
|
6184
|
+
inputRef.current?.ownerDocument.activeElement?.blur?.();
|
|
6185
|
+
setIsDragging(true);
|
|
6186
|
+
scrubStartYRef.current = e.clientY;
|
|
6187
|
+
scrubStartValueRef.current = startValue;
|
|
6188
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
6189
|
+
}, [value, isEditing, editText, commitEditText]);
|
|
6190
|
+
// When the step size changes during a drag (e.g. Shift/Alt pressed or released), reset the scrub reference point
|
|
6191
|
+
// to the current value and pointer position so only future movement uses the new step.
|
|
6192
|
+
useEffect(() => {
|
|
6193
|
+
if (isDragging) {
|
|
6194
|
+
scrubStartValueRef.current = value;
|
|
6195
|
+
scrubStartYRef.current = lastPointerYRef.current;
|
|
6100
6196
|
}
|
|
6101
|
-
|
|
6102
|
-
|
|
6197
|
+
}, [step]);
|
|
6198
|
+
const handleIconPointerMove = useCallback((e) => {
|
|
6199
|
+
if (!isDragging) {
|
|
6200
|
+
return;
|
|
6103
6201
|
}
|
|
6104
|
-
|
|
6105
|
-
//
|
|
6202
|
+
lastPointerYRef.current = e.clientY;
|
|
6203
|
+
// Dragging up (negative dy) should increment, dragging down should decrement.
|
|
6204
|
+
// Scale delta by step but round to display precision (not step) for smooth fine-grained control.
|
|
6205
|
+
const dy = scrubStartYRef.current - e.clientY;
|
|
6206
|
+
// 5 is just a number that "feels right" for the drag sensitivity — it determines how far the user needs to drag to change the value by 1 step.
|
|
6207
|
+
const delta = (dy * step) / 5;
|
|
6208
|
+
const raw = scrubStartValueRef.current + delta;
|
|
6209
|
+
const precisionFactor = Math.pow(10, displayPrecision);
|
|
6210
|
+
const rounded = Math.round(raw * precisionFactor) / precisionFactor;
|
|
6211
|
+
const constrained = constrainValue(rounded);
|
|
6212
|
+
setValue(constrained);
|
|
6213
|
+
tryCommitValue(constrained);
|
|
6214
|
+
}, [isDragging, step, displayPrecision, constrainValue, tryCommitValue]);
|
|
6215
|
+
const handleIconPointerUp = useCallback((e) => {
|
|
6216
|
+
setIsDragging(false);
|
|
6217
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
6218
|
+
}, []);
|
|
6219
|
+
const handleKeyDown = useCallback((event) => {
|
|
6220
|
+
// Commit on Enter and blur the input if the value is valid.
|
|
6106
6221
|
if (event.key === "Enter") {
|
|
6107
|
-
const
|
|
6108
|
-
if (
|
|
6109
|
-
|
|
6110
|
-
tryCommitValue(currVal);
|
|
6222
|
+
const committed = commitEditText(event.currentTarget.value);
|
|
6223
|
+
if (committed !== undefined) {
|
|
6224
|
+
inputRef.current?.blur();
|
|
6111
6225
|
}
|
|
6112
6226
|
}
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
setIsFocusedShiftKeyPressed(false);
|
|
6227
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
6228
|
+
event.preventDefault();
|
|
6229
|
+
const direction = event.key === "ArrowUp" ? 1 : -1;
|
|
6230
|
+
const newValue = constrainValue(Math.round((value + direction * step) / step) * step);
|
|
6231
|
+
setValue(newValue);
|
|
6232
|
+
tryCommitValue(newValue);
|
|
6233
|
+
// Update edit text to reflect the new value so the user sees the change
|
|
6234
|
+
setEditText(formatValue(newValue));
|
|
6122
6235
|
}
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6236
|
+
HandleKeyDown(event);
|
|
6237
|
+
}, [value, step, constrainValue, tryCommitValue, commitEditText, formatValue]);
|
|
6238
|
+
const id = useId("spin-button2");
|
|
6239
|
+
// Real-time validation: when editing, validate the expression; otherwise validate the committed value.
|
|
6240
|
+
// (validateValue already handles NaN, so no separate isNaN check needed.)
|
|
6241
|
+
const isInputInvalid = !validateValue(isEditing ? EvaluateExpression(editText) : value);
|
|
6242
|
+
const mergedClassName = mergeClasses(inputClasses.input, isInputInvalid ? inputClasses.invalid : "", props.className);
|
|
6243
|
+
const inputSlotClassName = mergeClasses(inputClasses.inputSlot, props.inputClassName);
|
|
6244
|
+
const formattedValue = formatValue(value);
|
|
6245
|
+
const handleFocus = useCallback(() => {
|
|
6246
|
+
setIsEditing(true);
|
|
6247
|
+
setEditText(formattedValue);
|
|
6248
|
+
}, [formattedValue]);
|
|
6249
|
+
const handleBlur = useCallback((event) => {
|
|
6250
|
+
// Skip blur handling if a drag just started (icon pointerDown already committed).
|
|
6251
|
+
if (isDragging) {
|
|
6126
6252
|
return;
|
|
6127
6253
|
}
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
};
|
|
6140
|
-
const spinButton = (jsx(SpinButton$1, { ref: ref, ...props, appearance: "outline", input: inputSlot, step: step, id: id, size: size, precision: fluentPrecision, displayValue: `${value.toFixed(displayPrecision)}${props.unit ? " " + props.unit : ""}`, value: value, onChange: handleChange, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, onBlur: HandleOnBlur, className: mergedClassName }));
|
|
6141
|
-
return props.infoLabel ? (jsxs("div", { className: classes.container, children: [jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), spinButton] })) : (spinButton);
|
|
6254
|
+
commitEditText(event.target.value);
|
|
6255
|
+
setIsEditing(false);
|
|
6256
|
+
HandleOnBlur(event);
|
|
6257
|
+
}, [commitEditText, isDragging]);
|
|
6258
|
+
const contentBefore = !props.disableDragButton && (isHovered || isDragging) && !isInputInvalid ? (jsx(ArrowBidirectionalUpDownFilled, { className: classes.icon, style: { cursor: isDragging ? "ns-resize" : "pointer" }, onPointerDown: handleIconPointerDown, onPointerMove: handleIconPointerMove, onPointerUp: handleIconPointerUp })) : undefined;
|
|
6259
|
+
const input = (jsx("div", { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => {
|
|
6260
|
+
if (!isDragging) {
|
|
6261
|
+
setIsHovered(false);
|
|
6262
|
+
}
|
|
6263
|
+
}, children: jsx(Input, { ref: mergedRef, id: id, appearance: "outline", size: size, className: mergedClassName, input: { className: inputSlotClassName }, value: isEditing ? editText : formattedValue, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, onBlur: handleBlur, contentBefore: contentBefore, contentAfter: props.unit }) }));
|
|
6264
|
+
return props.infoLabel ? (jsxs("div", { className: inputClasses.container, children: [jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), input] })) : (input);
|
|
6142
6265
|
});
|
|
6143
6266
|
|
|
6144
6267
|
const TextInput = (props) => {
|
|
@@ -6820,7 +6943,7 @@ const StatsServiceDefinition = {
|
|
|
6820
6943
|
horizontalLocation: "right",
|
|
6821
6944
|
verticalLocation: "top",
|
|
6822
6945
|
order: 300,
|
|
6823
|
-
|
|
6946
|
+
teachingMoment: false,
|
|
6824
6947
|
content: () => {
|
|
6825
6948
|
const sections = useOrderedObservableCollection(sectionsCollection);
|
|
6826
6949
|
const sectionContent = useObservableCollection(sectionContentCollection);
|
|
@@ -6909,7 +7032,7 @@ const ToolsServiceDefinition = {
|
|
|
6909
7032
|
horizontalLocation: "right",
|
|
6910
7033
|
verticalLocation: "top",
|
|
6911
7034
|
order: 400,
|
|
6912
|
-
|
|
7035
|
+
teachingMoment: false,
|
|
6913
7036
|
content: () => {
|
|
6914
7037
|
const sections = useOrderedObservableCollection(sectionsCollection);
|
|
6915
7038
|
const sectionContent = useObservableCollection(sectionContentCollection);
|
|
@@ -6927,12 +7050,337 @@ const ToolsServiceDefinition = {
|
|
|
6927
7050
|
},
|
|
6928
7051
|
};
|
|
6929
7052
|
|
|
7053
|
+
const useStyles$F = makeStyles({
|
|
7054
|
+
dropdown: {
|
|
7055
|
+
...UniformWidthStyling,
|
|
7056
|
+
},
|
|
7057
|
+
});
|
|
7058
|
+
/**
|
|
7059
|
+
* Wraps a dropdown in a property line
|
|
7060
|
+
* @param props - PropertyLineProps and DropdownProps
|
|
7061
|
+
* @returns property-line wrapped dropdown
|
|
7062
|
+
*/
|
|
7063
|
+
const DropdownPropertyLine = forwardRef((props, ref) => {
|
|
7064
|
+
DropdownPropertyLine.displayName = "DropdownPropertyLine";
|
|
7065
|
+
const classes = useStyles$F();
|
|
7066
|
+
return (jsx(PropertyLine, { ...props, ref: ref, children: jsx(Dropdown, { ...props, className: classes.dropdown }) }));
|
|
7067
|
+
});
|
|
7068
|
+
/**
|
|
7069
|
+
* Dropdown component for number values.
|
|
7070
|
+
*/
|
|
7071
|
+
const NumberDropdownPropertyLine = DropdownPropertyLine;
|
|
7072
|
+
/**
|
|
7073
|
+
* Dropdown component for string values
|
|
7074
|
+
*/
|
|
7075
|
+
const StringDropdownPropertyLine = DropdownPropertyLine;
|
|
7076
|
+
|
|
7077
|
+
/**
|
|
7078
|
+
* A slider primitive that wraps the Fluent UI Slider with step scaling, drag tracking, and optional notify-on-release behavior.
|
|
7079
|
+
* Follows the same pattern as other primitives (e.g. Switch) — no wrapper divs, just the Fluent component with logic.
|
|
7080
|
+
* @param props
|
|
7081
|
+
* @returns Slider component
|
|
7082
|
+
*/
|
|
7083
|
+
const Slider = (props) => {
|
|
7084
|
+
Slider.displayName = "Slider";
|
|
7085
|
+
const { size } = useContext(ToolContext);
|
|
7086
|
+
const [value, setValue] = useState(props.value ?? 0);
|
|
7087
|
+
const pendingValueRef = useRef(undefined);
|
|
7088
|
+
const isDraggingRef = useRef(false);
|
|
7089
|
+
// NOTE: The Fluent slider will add tick marks if the step prop is anything other than undefined.
|
|
7090
|
+
// To avoid this, we scale the min/max based on the step so we can always make step undefined.
|
|
7091
|
+
// The actual step size in the Fluent slider is 1 when it is set to undefined.
|
|
7092
|
+
const min = props.min ?? 0;
|
|
7093
|
+
const max = props.max ?? 100;
|
|
7094
|
+
const step = props.step ?? 1;
|
|
7095
|
+
useEffect(() => {
|
|
7096
|
+
!isDraggingRef.current && setValue(props.value ?? 0); // Update local state when props.value changes as long as user is not actively dragging
|
|
7097
|
+
}, [props.value]);
|
|
7098
|
+
const handleSliderChange = (_, data) => {
|
|
7099
|
+
const newValue = data.value * step;
|
|
7100
|
+
setValue(newValue);
|
|
7101
|
+
if (props.notifyOnlyOnRelease) {
|
|
7102
|
+
// Store the value but don't notify parent yet
|
|
7103
|
+
pendingValueRef.current = newValue;
|
|
7104
|
+
}
|
|
7105
|
+
else {
|
|
7106
|
+
// Notify parent as slider changes
|
|
7107
|
+
props.onChange(newValue);
|
|
7108
|
+
}
|
|
7109
|
+
};
|
|
7110
|
+
const handleSliderPointerDown = () => {
|
|
7111
|
+
isDraggingRef.current = true;
|
|
7112
|
+
};
|
|
7113
|
+
const handleSliderPointerUp = () => {
|
|
7114
|
+
if (props.notifyOnlyOnRelease && isDraggingRef.current && pendingValueRef.current !== undefined) {
|
|
7115
|
+
props.onChange(pendingValueRef.current);
|
|
7116
|
+
pendingValueRef.current = undefined;
|
|
7117
|
+
}
|
|
7118
|
+
isDraggingRef.current = false;
|
|
7119
|
+
};
|
|
7120
|
+
return (jsx(Slider$1, { className: props.className, size: size, min: min / step, max: max / step, step: undefined, value: value / step, disabled: props.disabled, onChange: handleSliderChange, onPointerDown: () => {
|
|
7121
|
+
handleSliderPointerDown();
|
|
7122
|
+
props.onPointerDown?.();
|
|
7123
|
+
}, onPointerUp: () => {
|
|
7124
|
+
handleSliderPointerUp();
|
|
7125
|
+
props.onPointerUp?.();
|
|
7126
|
+
} }));
|
|
7127
|
+
};
|
|
7128
|
+
|
|
7129
|
+
const useSyncedSliderStyles = makeStyles({
|
|
7130
|
+
container: { display: "flex", minWidth: 0 },
|
|
7131
|
+
syncedSlider: {
|
|
7132
|
+
flex: "1 1 0",
|
|
7133
|
+
flexDirection: "row",
|
|
7134
|
+
display: "flex",
|
|
7135
|
+
alignItems: "center",
|
|
7136
|
+
minWidth: 0,
|
|
7137
|
+
},
|
|
7138
|
+
slider: {
|
|
7139
|
+
flex: "1 1 auto",
|
|
7140
|
+
minWidth: "75px",
|
|
7141
|
+
maxWidth: "75px",
|
|
7142
|
+
},
|
|
7143
|
+
compactSlider: {
|
|
7144
|
+
flex: "1 1 auto",
|
|
7145
|
+
minWidth: "50px", // Allow shrinking for compact mode
|
|
7146
|
+
maxWidth: "75px",
|
|
7147
|
+
},
|
|
7148
|
+
growSlider: {
|
|
7149
|
+
flex: "1 1 auto",
|
|
7150
|
+
minWidth: "50px",
|
|
7151
|
+
// No maxWidth - slider grows to fill available space
|
|
7152
|
+
},
|
|
7153
|
+
compactSpinButton: {
|
|
7154
|
+
width: "65px",
|
|
7155
|
+
minWidth: "65px",
|
|
7156
|
+
maxWidth: "65px",
|
|
7157
|
+
},
|
|
7158
|
+
compactSpinButtonInput: {
|
|
7159
|
+
minWidth: "0",
|
|
7160
|
+
},
|
|
7161
|
+
});
|
|
7162
|
+
/**
|
|
7163
|
+
* Component which synchronizes a slider and an input field, allowing the user to change the value using either control
|
|
7164
|
+
* @param props
|
|
7165
|
+
* @returns SyncedSlider component
|
|
7166
|
+
*/
|
|
7167
|
+
const SyncedSliderInput = (props) => {
|
|
7168
|
+
SyncedSliderInput.displayName = "SyncedSliderInput";
|
|
7169
|
+
const { infoLabel, ...passthroughProps } = props;
|
|
7170
|
+
const classes = useSyncedSliderStyles();
|
|
7171
|
+
const [value, setValue] = useState(props.value ?? 0);
|
|
7172
|
+
const pendingValueRef = useRef(undefined);
|
|
7173
|
+
const isDraggingRef = useRef(false);
|
|
7174
|
+
useEffect(() => {
|
|
7175
|
+
!isDraggingRef.current && setValue(props.value ?? 0); // Update local state when props.value changes as long as user is not actively dragging
|
|
7176
|
+
}, [props.value]);
|
|
7177
|
+
const handleSliderChange = (newValue) => {
|
|
7178
|
+
setValue(newValue);
|
|
7179
|
+
if (props.notifyOnlyOnRelease) {
|
|
7180
|
+
// Store the value but don't notify parent yet
|
|
7181
|
+
pendingValueRef.current = newValue;
|
|
7182
|
+
}
|
|
7183
|
+
else {
|
|
7184
|
+
// Notify parent as slider changes
|
|
7185
|
+
props.onChange(newValue);
|
|
7186
|
+
}
|
|
7187
|
+
};
|
|
7188
|
+
const handleSliderPointerDown = () => {
|
|
7189
|
+
isDraggingRef.current = true;
|
|
7190
|
+
};
|
|
7191
|
+
const handleSliderPointerUp = () => {
|
|
7192
|
+
if (props.notifyOnlyOnRelease && isDraggingRef.current && pendingValueRef.current !== undefined) {
|
|
7193
|
+
props.onChange(pendingValueRef.current);
|
|
7194
|
+
pendingValueRef.current = undefined;
|
|
7195
|
+
}
|
|
7196
|
+
isDraggingRef.current = false;
|
|
7197
|
+
};
|
|
7198
|
+
const handleInputChange = (value) => {
|
|
7199
|
+
setValue(value);
|
|
7200
|
+
props.onChange(value); // Input always updates immediately
|
|
7201
|
+
};
|
|
7202
|
+
const hasSlider = props.min !== undefined && props.max !== undefined;
|
|
7203
|
+
// Determine Slider className based on props
|
|
7204
|
+
const getSliderClassName = () => {
|
|
7205
|
+
if (props.growSlider) {
|
|
7206
|
+
return classes.growSlider;
|
|
7207
|
+
}
|
|
7208
|
+
if (props.compact) {
|
|
7209
|
+
return classes.compactSlider;
|
|
7210
|
+
}
|
|
7211
|
+
return classes.slider;
|
|
7212
|
+
};
|
|
7213
|
+
return (jsxs("div", { className: classes.container, children: [infoLabel && jsx(InfoLabel, { ...infoLabel, htmlFor: "syncedSlider" }), jsxs("div", { id: "syncedSlider", className: classes.syncedSlider, children: [hasSlider && (jsx(Slider, { className: getSliderClassName(), value: value, onChange: handleSliderChange, min: props.min, max: props.max, step: props.step, disabled: props.disabled, onPointerDown: handleSliderPointerDown, onPointerUp: handleSliderPointerUp })), jsx(SpinButton, { ...passthroughProps, className: hasSlider || props.compact ? classes.compactSpinButton : undefined, inputClassName: hasSlider || props.compact ? classes.compactSpinButtonInput : undefined, value: value, onChange: handleInputChange, step: props.step, disableDragButton: true })] })] }));
|
|
7214
|
+
};
|
|
7215
|
+
|
|
7216
|
+
/**
|
|
7217
|
+
* Renders a simple wrapper around the SyncedSliderInput
|
|
7218
|
+
* @param props
|
|
7219
|
+
* @returns
|
|
7220
|
+
*/
|
|
7221
|
+
const SyncedSliderPropertyLine = forwardRef((props, ref) => {
|
|
7222
|
+
SyncedSliderPropertyLine.displayName = "SyncedSliderPropertyLine";
|
|
7223
|
+
const { label, description, ...sliderProps } = props;
|
|
7224
|
+
return (jsx(PropertyLine, { ref: ref, ...props, children: jsx(SyncedSliderInput, { ...sliderProps }) }));
|
|
7225
|
+
});
|
|
7226
|
+
|
|
7227
|
+
const WatcherSettingDescriptor = {
|
|
7228
|
+
key: "WatcherSettings",
|
|
7229
|
+
defaultValue: {
|
|
7230
|
+
mode: "intercept",
|
|
7231
|
+
},
|
|
7232
|
+
};
|
|
7233
|
+
const WatcherServiceIdentity = Symbol("WatcherService");
|
|
7234
|
+
const WatcherServiceDefinition = {
|
|
7235
|
+
friendlyName: "Watcher Service",
|
|
7236
|
+
produces: [WatcherServiceIdentity],
|
|
7237
|
+
consumes: [SettingsStoreIdentity],
|
|
7238
|
+
factory: (settingsStore) => {
|
|
7239
|
+
let refreshObservable = null;
|
|
7240
|
+
let pollingHandle = null;
|
|
7241
|
+
const applySettings = () => {
|
|
7242
|
+
const settings = settingsStore.readSetting(WatcherSettingDescriptor);
|
|
7243
|
+
if (pollingHandle !== null) {
|
|
7244
|
+
clearInterval(pollingHandle);
|
|
7245
|
+
pollingHandle = null;
|
|
7246
|
+
}
|
|
7247
|
+
if (settings.mode === "intercept") {
|
|
7248
|
+
if (refreshObservable) {
|
|
7249
|
+
refreshObservable.clear();
|
|
7250
|
+
refreshObservable = null;
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
else {
|
|
7254
|
+
const pollingObservable = refreshObservable ?? (refreshObservable = new Observable());
|
|
7255
|
+
if (settings.mode === "polling") {
|
|
7256
|
+
pollingHandle = window.setInterval(() => {
|
|
7257
|
+
pollingObservable.notifyObservers();
|
|
7258
|
+
}, settings.interval);
|
|
7259
|
+
}
|
|
7260
|
+
}
|
|
7261
|
+
};
|
|
7262
|
+
const settingsStoreObserver = settingsStore.onChanged.add((key) => {
|
|
7263
|
+
if (key === WatcherSettingDescriptor.key) {
|
|
7264
|
+
applySettings();
|
|
7265
|
+
}
|
|
7266
|
+
});
|
|
7267
|
+
applySettings();
|
|
7268
|
+
return {
|
|
7269
|
+
watchProperty(target, propertyKey, onChanged) {
|
|
7270
|
+
if (refreshObservable) {
|
|
7271
|
+
let previousValue = target[propertyKey];
|
|
7272
|
+
const observer = refreshObservable.add(() => {
|
|
7273
|
+
const currentValue = target[propertyKey];
|
|
7274
|
+
if (!Object.is(previousValue, currentValue)) {
|
|
7275
|
+
previousValue = currentValue;
|
|
7276
|
+
onChanged(currentValue);
|
|
7277
|
+
}
|
|
7278
|
+
});
|
|
7279
|
+
return {
|
|
7280
|
+
dispose: () => observer.remove(),
|
|
7281
|
+
};
|
|
7282
|
+
}
|
|
7283
|
+
else {
|
|
7284
|
+
return InterceptProperty(target, propertyKey, {
|
|
7285
|
+
afterSet: (value) => onChanged(value),
|
|
7286
|
+
});
|
|
7287
|
+
}
|
|
7288
|
+
},
|
|
7289
|
+
refresh: () => {
|
|
7290
|
+
refreshObservable?.notifyObservers();
|
|
7291
|
+
},
|
|
7292
|
+
dispose: () => {
|
|
7293
|
+
if (pollingHandle !== null) {
|
|
7294
|
+
clearInterval(pollingHandle);
|
|
7295
|
+
pollingHandle = null;
|
|
7296
|
+
}
|
|
7297
|
+
refreshObservable?.clear();
|
|
7298
|
+
refreshObservable = null;
|
|
7299
|
+
settingsStoreObserver.remove();
|
|
7300
|
+
},
|
|
7301
|
+
};
|
|
7302
|
+
},
|
|
7303
|
+
};
|
|
7304
|
+
const WatchModes = [
|
|
7305
|
+
{ label: "Interception", value: "intercept" },
|
|
7306
|
+
{ label: "Polling", value: "polling" },
|
|
7307
|
+
{ label: "Manual", value: "manual" },
|
|
7308
|
+
];
|
|
7309
|
+
const WatcherSettingsServiceDefinition = {
|
|
7310
|
+
friendlyName: "Watcher Settings Service",
|
|
7311
|
+
consumes: [SettingsServiceIdentity],
|
|
7312
|
+
factory: (settingsService) => {
|
|
7313
|
+
const settingsRegistration = settingsService.addSectionContent({
|
|
7314
|
+
key: "watcherSettings",
|
|
7315
|
+
section: "UI",
|
|
7316
|
+
component: () => {
|
|
7317
|
+
const [watcherSettings, setWatcherSettings] = useSetting(WatcherSettingDescriptor);
|
|
7318
|
+
return (jsxs(Fragment, { children: [jsx(DropdownPropertyLine, { label: "Property Watch Mode", description: `Specifies how Inspector watches entity properties for changes. "Interception" sees changes instantly, but for complex scenes can impact performance. "Polling" has less performance impact on complex scenes, but changes are only detected at the specified interval. "Manual" requires the "Refresh" button in the toolbar to be pressed.`, options: WatchModes, value: watcherSettings.mode, onChange: (value) => setWatcherSettings((prev) => {
|
|
7319
|
+
return { interval: 250, ...prev, mode: value };
|
|
7320
|
+
}) }), jsx(Collapse, { visible: watcherSettings.mode === "polling", children: jsx(SyncedSliderPropertyLine, { label: "Polling Interval", description: "A smaller polling interval will detect changes faster but may impact performance more.", min: 30, max: 1000, step: 10, unit: "ms", value: watcherSettings.mode === "polling" ? watcherSettings.interval : NaN, onChange: (value) => setWatcherSettings((prev) => {
|
|
7321
|
+
return { ...prev, interval: value };
|
|
7322
|
+
}) }) })] }));
|
|
7323
|
+
},
|
|
7324
|
+
});
|
|
7325
|
+
return {
|
|
7326
|
+
dispose: () => {
|
|
7327
|
+
settingsRegistration.dispose();
|
|
7328
|
+
},
|
|
7329
|
+
};
|
|
7330
|
+
},
|
|
7331
|
+
};
|
|
7332
|
+
const WatcherRefreshToolbarServiceDefinition = {
|
|
7333
|
+
friendlyName: "Watcher Refresh Toolbar Service",
|
|
7334
|
+
consumes: [WatcherServiceIdentity, SettingsStoreIdentity, ShellServiceIdentity],
|
|
7335
|
+
factory: (watcherService, settingsStore, shellService) => {
|
|
7336
|
+
let toolbarItemRegistration = null;
|
|
7337
|
+
const updateToolbar = () => {
|
|
7338
|
+
const settings = settingsStore.readSetting(WatcherSettingDescriptor);
|
|
7339
|
+
if (settings.mode === "manual") {
|
|
7340
|
+
if (!toolbarItemRegistration) {
|
|
7341
|
+
toolbarItemRegistration = shellService.addToolbarItem({
|
|
7342
|
+
key: "Watcher Refresh",
|
|
7343
|
+
displayName: "Refresh Properties",
|
|
7344
|
+
verticalLocation: "bottom",
|
|
7345
|
+
horizontalLocation: "right",
|
|
7346
|
+
order: 200 /* DefaultToolbarItemOrder.RefreshProperties */,
|
|
7347
|
+
teachingMoment: {
|
|
7348
|
+
title: "Refresh Properties",
|
|
7349
|
+
description: "Press this button to manually refresh all UI bound to scene state. This is only available when Property Watch Mode is set to Manual in the settings pane.",
|
|
7350
|
+
},
|
|
7351
|
+
component: () => {
|
|
7352
|
+
return (jsx(Button, { appearance: "subtle", icon: ArrowClockwiseRegular, title: "Update all UI (e.g. Scene Explorer, Properties, etc.) bound to properties of entities (Meshes, Materials, etc.)", onClick: () => watcherService.refresh() }));
|
|
7353
|
+
},
|
|
7354
|
+
});
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
7357
|
+
else {
|
|
7358
|
+
toolbarItemRegistration?.dispose();
|
|
7359
|
+
toolbarItemRegistration = null;
|
|
7360
|
+
}
|
|
7361
|
+
};
|
|
7362
|
+
updateToolbar();
|
|
7363
|
+
const settingsStoreObserver = settingsStore.onChanged.add((key) => {
|
|
7364
|
+
if (key === WatcherSettingDescriptor.key) {
|
|
7365
|
+
updateToolbar();
|
|
7366
|
+
}
|
|
7367
|
+
});
|
|
7368
|
+
return {
|
|
7369
|
+
dispose: () => {
|
|
7370
|
+
toolbarItemRegistration?.dispose();
|
|
7371
|
+
toolbarItemRegistration = null;
|
|
7372
|
+
settingsStoreObserver.remove();
|
|
7373
|
+
},
|
|
7374
|
+
};
|
|
7375
|
+
},
|
|
7376
|
+
};
|
|
7377
|
+
|
|
6930
7378
|
const GizmoServiceIdentity = Symbol("GizmoService");
|
|
6931
7379
|
const GizmoServiceDefinition = {
|
|
6932
7380
|
friendlyName: "Gizmo Service",
|
|
6933
7381
|
produces: [GizmoServiceIdentity],
|
|
6934
|
-
consumes: [SceneContextIdentity, SelectionServiceIdentity],
|
|
6935
|
-
factory: (sceneContext, selectionService) => {
|
|
7382
|
+
consumes: [SceneContextIdentity, SelectionServiceIdentity, WatcherServiceIdentity],
|
|
7383
|
+
factory: (sceneContext, selectionService, watcherService) => {
|
|
6936
7384
|
// Ref-counted utility layers, shared across consumers.
|
|
6937
7385
|
const utilityLayers = new WeakMap();
|
|
6938
7386
|
const getUtilityLayer = (scene, layer = "default") => {
|
|
@@ -7031,13 +7479,11 @@ const GizmoServiceDefinition = {
|
|
|
7031
7479
|
currentKeepDepthUtilityLayerRef = null;
|
|
7032
7480
|
};
|
|
7033
7481
|
gm.coordinatesMode = coordinatesModeState;
|
|
7034
|
-
coordinatesModeInterceptToken =
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
}
|
|
7040
|
-
},
|
|
7482
|
+
coordinatesModeInterceptToken = watcherService.watchProperty(gm, "coordinatesMode", (value) => {
|
|
7483
|
+
if (value !== coordinatesModeState) {
|
|
7484
|
+
coordinatesModeState = value;
|
|
7485
|
+
coordinatesModeObservable.notifyObservers();
|
|
7486
|
+
}
|
|
7041
7487
|
});
|
|
7042
7488
|
currentGizmoManager = gm;
|
|
7043
7489
|
}
|
|
@@ -7210,7 +7656,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
7210
7656
|
keywords: ["creation", "tools"],
|
|
7211
7657
|
...BabylonWebResources,
|
|
7212
7658
|
author: { name: "Babylon.js", forumUserName: "" },
|
|
7213
|
-
getExtensionModuleAsync: async () => await import('./quickCreateToolsService-
|
|
7659
|
+
getExtensionModuleAsync: async () => await import('./quickCreateToolsService-DeZ7ZJOC.js'),
|
|
7214
7660
|
},
|
|
7215
7661
|
{
|
|
7216
7662
|
name: "Reflector",
|
|
@@ -7218,116 +7664,10 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
7218
7664
|
keywords: ["reflector", "bridge", "sync", "sandbox", "tools"],
|
|
7219
7665
|
...BabylonWebResources,
|
|
7220
7666
|
author: { name: "Babylon.js", forumUserName: "" },
|
|
7221
|
-
getExtensionModuleAsync: async () => await import('./reflectorService-
|
|
7667
|
+
getExtensionModuleAsync: async () => await import('./reflectorService-DE0Ic3N5.js'),
|
|
7222
7668
|
},
|
|
7223
7669
|
]);
|
|
7224
7670
|
|
|
7225
|
-
const useSyncedSliderStyles = makeStyles({
|
|
7226
|
-
container: { display: "flex", minWidth: 0 },
|
|
7227
|
-
syncedSlider: {
|
|
7228
|
-
flex: "1 1 0",
|
|
7229
|
-
flexDirection: "row",
|
|
7230
|
-
display: "flex",
|
|
7231
|
-
alignItems: "center",
|
|
7232
|
-
minWidth: 0,
|
|
7233
|
-
},
|
|
7234
|
-
slider: {
|
|
7235
|
-
flex: "1 1 auto",
|
|
7236
|
-
minWidth: "75px",
|
|
7237
|
-
maxWidth: "75px",
|
|
7238
|
-
},
|
|
7239
|
-
compactSlider: {
|
|
7240
|
-
flex: "1 1 auto",
|
|
7241
|
-
minWidth: "50px", // Allow shrinking for compact mode
|
|
7242
|
-
maxWidth: "75px",
|
|
7243
|
-
},
|
|
7244
|
-
growSlider: {
|
|
7245
|
-
flex: "1 1 auto",
|
|
7246
|
-
minWidth: "50px",
|
|
7247
|
-
// No maxWidth - slider grows to fill available space
|
|
7248
|
-
},
|
|
7249
|
-
compactSpinButton: {
|
|
7250
|
-
width: "65px",
|
|
7251
|
-
minWidth: "65px",
|
|
7252
|
-
maxWidth: "65px",
|
|
7253
|
-
},
|
|
7254
|
-
compactSpinButtonInput: {
|
|
7255
|
-
minWidth: "0",
|
|
7256
|
-
},
|
|
7257
|
-
});
|
|
7258
|
-
/**
|
|
7259
|
-
* Component which synchronizes a slider and an input field, allowing the user to change the value using either control
|
|
7260
|
-
* @param props
|
|
7261
|
-
* @returns SyncedSlider component
|
|
7262
|
-
*/
|
|
7263
|
-
const SyncedSliderInput = (props) => {
|
|
7264
|
-
SyncedSliderInput.displayName = "SyncedSliderInput";
|
|
7265
|
-
const { infoLabel, ...passthroughProps } = props;
|
|
7266
|
-
const classes = useSyncedSliderStyles();
|
|
7267
|
-
const { size } = useContext(ToolContext);
|
|
7268
|
-
const [value, setValue] = useState(props.value ?? 0);
|
|
7269
|
-
const pendingValueRef = useRef(undefined);
|
|
7270
|
-
const isDraggingRef = useRef(false);
|
|
7271
|
-
// NOTE: The Fluent slider will add tick marks if the step prop is anything other than undefined.
|
|
7272
|
-
// To avoid this, we scale the min/max based on the step so we can always make step undefined.
|
|
7273
|
-
// The actual step size in the Fluent slider is 1 when it is ste to undefined.
|
|
7274
|
-
const min = props.min ?? 0;
|
|
7275
|
-
const max = props.max ?? 100;
|
|
7276
|
-
const step = props.step ?? 1;
|
|
7277
|
-
useEffect(() => {
|
|
7278
|
-
!isDraggingRef.current && setValue(props.value ?? 0); // Update local state when props.value changes as long as user is not actively dragging
|
|
7279
|
-
}, [props.value]);
|
|
7280
|
-
const handleSliderChange = (_, data) => {
|
|
7281
|
-
const newValue = data.value * step;
|
|
7282
|
-
setValue(newValue);
|
|
7283
|
-
if (props.notifyOnlyOnRelease) {
|
|
7284
|
-
// Store the value but don't notify parent yet
|
|
7285
|
-
pendingValueRef.current = newValue;
|
|
7286
|
-
}
|
|
7287
|
-
else {
|
|
7288
|
-
// Notify parent as slider changes
|
|
7289
|
-
props.onChange(newValue);
|
|
7290
|
-
}
|
|
7291
|
-
};
|
|
7292
|
-
const handleSliderPointerDown = () => {
|
|
7293
|
-
isDraggingRef.current = true;
|
|
7294
|
-
};
|
|
7295
|
-
const handleSliderPointerUp = () => {
|
|
7296
|
-
if (props.notifyOnlyOnRelease && isDraggingRef.current && pendingValueRef.current !== undefined) {
|
|
7297
|
-
props.onChange(pendingValueRef.current);
|
|
7298
|
-
pendingValueRef.current = undefined;
|
|
7299
|
-
}
|
|
7300
|
-
isDraggingRef.current = false;
|
|
7301
|
-
};
|
|
7302
|
-
const handleInputChange = (value) => {
|
|
7303
|
-
setValue(value);
|
|
7304
|
-
props.onChange(value); // Input always updates immediately
|
|
7305
|
-
};
|
|
7306
|
-
const hasSlider = props.min !== undefined && props.max !== undefined;
|
|
7307
|
-
// Determine Slider className based on props
|
|
7308
|
-
const getSliderClassName = () => {
|
|
7309
|
-
if (props.growSlider) {
|
|
7310
|
-
return classes.growSlider;
|
|
7311
|
-
}
|
|
7312
|
-
if (props.compact) {
|
|
7313
|
-
return classes.compactSlider;
|
|
7314
|
-
}
|
|
7315
|
-
return classes.slider;
|
|
7316
|
-
};
|
|
7317
|
-
return (jsxs("div", { className: classes.container, children: [infoLabel && jsx(InfoLabel, { ...infoLabel, htmlFor: "syncedSlider" }), jsxs("div", { id: "syncedSlider", className: classes.syncedSlider, children: [hasSlider && (jsx(Slider, { ...passthroughProps, className: getSliderClassName(), size: size, min: min / step, max: max / step, step: undefined, value: value / step, onChange: handleSliderChange, onPointerDown: handleSliderPointerDown, onPointerUp: handleSliderPointerUp })), jsx(SpinButton, { ...passthroughProps, className: hasSlider || props.compact ? classes.compactSpinButton : undefined, inputClassName: hasSlider || props.compact ? classes.compactSpinButtonInput : undefined, value: value, onChange: handleInputChange, step: props.step })] })] }));
|
|
7318
|
-
};
|
|
7319
|
-
|
|
7320
|
-
/**
|
|
7321
|
-
* Renders a simple wrapper around the SyncedSliderInput
|
|
7322
|
-
* @param props
|
|
7323
|
-
* @returns
|
|
7324
|
-
*/
|
|
7325
|
-
const SyncedSliderPropertyLine = forwardRef((props, ref) => {
|
|
7326
|
-
SyncedSliderPropertyLine.displayName = "SyncedSliderPropertyLine";
|
|
7327
|
-
const { label, description, ...sliderProps } = props;
|
|
7328
|
-
return (jsx(PropertyLine, { ref: ref, ...props, children: jsx(SyncedSliderInput, { ...sliderProps }) }));
|
|
7329
|
-
});
|
|
7330
|
-
|
|
7331
7671
|
/**
|
|
7332
7672
|
* Reusable component which renders a color property line containing a label, colorPicker popout, and expandable RGBA values
|
|
7333
7673
|
* The expandable RGBA values are synced sliders that allow the user to modify the color's RGBA values directly
|
|
@@ -7362,30 +7702,6 @@ const ColorSliders = ({ color, onSliderChange }) => (jsxs(Fragment, { children:
|
|
|
7362
7702
|
const Color3PropertyLine = ColorPropertyLine;
|
|
7363
7703
|
const Color4PropertyLine = ColorPropertyLine;
|
|
7364
7704
|
|
|
7365
|
-
const useStyles$F = makeStyles({
|
|
7366
|
-
dropdown: {
|
|
7367
|
-
...UniformWidthStyling,
|
|
7368
|
-
},
|
|
7369
|
-
});
|
|
7370
|
-
/**
|
|
7371
|
-
* Wraps a dropdown in a property line
|
|
7372
|
-
* @param props - PropertyLineProps and DropdownProps
|
|
7373
|
-
* @returns property-line wrapped dropdown
|
|
7374
|
-
*/
|
|
7375
|
-
const DropdownPropertyLine = forwardRef((props, ref) => {
|
|
7376
|
-
DropdownPropertyLine.displayName = "DropdownPropertyLine";
|
|
7377
|
-
const classes = useStyles$F();
|
|
7378
|
-
return (jsx(PropertyLine, { ...props, ref: ref, children: jsx(Dropdown, { ...props, className: classes.dropdown }) }));
|
|
7379
|
-
});
|
|
7380
|
-
/**
|
|
7381
|
-
* Dropdown component for number values.
|
|
7382
|
-
*/
|
|
7383
|
-
const NumberDropdownPropertyLine = DropdownPropertyLine;
|
|
7384
|
-
/**
|
|
7385
|
-
* Dropdown component for string values
|
|
7386
|
-
*/
|
|
7387
|
-
const StringDropdownPropertyLine = DropdownPropertyLine;
|
|
7388
|
-
|
|
7389
7705
|
/**
|
|
7390
7706
|
* Wraps a text input in a property line
|
|
7391
7707
|
* @param props - PropertyLineProps and InputProps
|
|
@@ -7430,21 +7746,21 @@ const TensorPropertyLine = (props) => {
|
|
|
7430
7746
|
useEffect(() => {
|
|
7431
7747
|
setVector(props.value);
|
|
7432
7748
|
}, [props.value, props.expandedContent]);
|
|
7433
|
-
return (jsx(PropertyLine, { ...props, expandedContent: vector ? jsx(VectorSliders, { vector: vector, min: min, max: max, unit: props.unit, step: props.step, converted: converted, onChange: onChange }) : undefined, children: jsx(Body1, { children: `[${formatted(props.value.x)}, ${formatted(props.value.y)}${HasZ(props.value) ? `, ${formatted(props.value.z)}` : ""}${HasW(props.value) ? `, ${formatted(props.value.w)}` : ""}]` }) }));
|
|
7749
|
+
return (jsx(PropertyLine, { ...props, expandedContent: jsxs(Fragment, { children: [props.expandedContent, vector ? (jsx(VectorSliders, { vector: vector, min: min, max: max, unit: props.unit, step: props.step, precision: props.precision, converted: converted, onChange: onChange })) : undefined] }), children: jsx(Body1, { children: `[${formatted(props.value.x)}, ${formatted(props.value.y)}${HasZ(props.value) ? `, ${formatted(props.value.z)}` : ""}${HasW(props.value) ? `, ${formatted(props.value.w)}` : ""}]` }) }));
|
|
7434
7750
|
};
|
|
7435
|
-
const VectorSliders = ({ vector, min, max, unit, step, converted, onChange }) => (jsxs(Fragment, { children: [jsx(
|
|
7751
|
+
const VectorSliders = ({ vector, min, max, unit, step, precision, converted, onChange }) => (jsxs(Fragment, { children: [jsx(NumberInputPropertyLine, { label: "X", value: converted(vector.x), min: min, max: max, onChange: (val) => onChange(val, "x"), unit: unit, step: step, precision: precision }), jsx(NumberInputPropertyLine, { label: "Y", value: converted(vector.y), min: min, max: max, onChange: (val) => onChange(val, "y"), unit: unit, step: step, precision: precision }), HasZ(vector) && (jsx(NumberInputPropertyLine, { label: "Z", value: converted(vector.z), min: min, max: max, onChange: (val) => onChange(val, "z"), unit: unit, step: step, precision: precision })), HasW(vector) && (jsx(NumberInputPropertyLine, { label: "W", value: converted(vector.w), min: min, max: max, onChange: (val) => onChange(val, "w"), unit: unit, step: step, precision: precision }))] }));
|
|
7436
7752
|
const ToDegreesConverter = { from: Tools.ToDegrees, to: Tools.ToRadians };
|
|
7437
7753
|
const RotationVectorPropertyLine = (props) => {
|
|
7438
7754
|
RotationVectorPropertyLine.displayName = "RotationVectorPropertyLine";
|
|
7439
|
-
const
|
|
7440
|
-
const
|
|
7441
|
-
return (jsx(Vector3PropertyLine, { ...props, unit: props.useDegrees ? "
|
|
7755
|
+
const step = props.useDegrees ? 1 : 0.01;
|
|
7756
|
+
const precision = props.useDegrees ? 1 : 2;
|
|
7757
|
+
return (jsx(Vector3PropertyLine, { ...props, unit: props.useDegrees ? "°" : "rad", valueConverter: props.useDegrees ? ToDegreesConverter : undefined, step: step, precision: precision }));
|
|
7442
7758
|
};
|
|
7443
7759
|
const QuaternionPropertyLineInternal = TensorPropertyLine;
|
|
7444
7760
|
const QuaternionPropertyLine = (props) => {
|
|
7445
7761
|
QuaternionPropertyLine.displayName = "QuaternionPropertyLine";
|
|
7446
|
-
const
|
|
7447
|
-
const
|
|
7762
|
+
const step = props.useDegrees ? 1 : 0.01;
|
|
7763
|
+
const precision = props.useDegrees ? 1 : 2;
|
|
7448
7764
|
const [quat, setQuat] = useState(props.value);
|
|
7449
7765
|
useEffect(() => {
|
|
7450
7766
|
setQuat(props.value);
|
|
@@ -7459,7 +7775,7 @@ const QuaternionPropertyLine = (props) => {
|
|
|
7459
7775
|
const quat = Quaternion.FromEulerAngles(val.x, val.y, val.z);
|
|
7460
7776
|
onQuatChange(quat);
|
|
7461
7777
|
};
|
|
7462
|
-
return useEuler ? (jsx(Vector3PropertyLine, { ...restProps, nullable: false, ignoreNullable: false, value: quat.toEulerAngles(), valueConverter: ToDegreesConverter,
|
|
7778
|
+
return useEuler ? (jsx(Vector3PropertyLine, { ...restProps, nullable: false, ignoreNullable: false, value: quat.toEulerAngles(), valueConverter: ToDegreesConverter, onChange: onEulerChange, unit: props.useDegrees ? "°" : "rad", step: step, precision: precision, expandedContent: jsx(TextPropertyLine, { label: "Quaternion", value: `[${quat.x.toFixed(4)}, ${quat.y.toFixed(4)}, ${quat.z.toFixed(4)}, ${quat.w.toFixed(4)}]` }) })) : (jsx(QuaternionPropertyLineInternal, { ...props, nullable: false, value: quat, onChange: onQuatChange, unit: props.useDegrees ? "°" : "rad", step: step, precision: precision }));
|
|
7463
7779
|
};
|
|
7464
7780
|
const Vector2PropertyLine = TensorPropertyLine;
|
|
7465
7781
|
const Vector3PropertyLine = TensorPropertyLine;
|
|
@@ -7974,7 +8290,7 @@ const ThemeSelectorServiceDefinition = {
|
|
|
7974
8290
|
key: "ThemeSelector",
|
|
7975
8291
|
horizontalLocation: "right",
|
|
7976
8292
|
verticalLocation: "top",
|
|
7977
|
-
|
|
8293
|
+
teachingMoment: false,
|
|
7978
8294
|
order: -300,
|
|
7979
8295
|
component: () => {
|
|
7980
8296
|
const classes = useStyles$E();
|
|
@@ -8039,7 +8355,7 @@ function MakeModularTool(options) {
|
|
|
8039
8355
|
const [requiredExtensions, setRequiredExtensions] = useState();
|
|
8040
8356
|
const [requiredExtensionsDeferred, setRequiredExtensionsDeferred] = useState();
|
|
8041
8357
|
const [extensionInstallError, setExtensionInstallError] = useState();
|
|
8042
|
-
const [
|
|
8358
|
+
const [bootstrapServices, setBootstrapServices] = useState();
|
|
8043
8359
|
// This is the main async initialization.
|
|
8044
8360
|
useEffect(() => {
|
|
8045
8361
|
const initializeExtensionManagerAsync = async () => {
|
|
@@ -8050,17 +8366,22 @@ function MakeModularTool(options) {
|
|
|
8050
8366
|
produces: [SettingsStoreIdentity],
|
|
8051
8367
|
factory: () => settingsStore,
|
|
8052
8368
|
});
|
|
8369
|
+
// Register watcher service early since many other services will rely on it.
|
|
8370
|
+
// TODO: Really this should be in the Inspector layer, but we would need a way
|
|
8371
|
+
// to setup the WatcherContext.Provider before the root component is rendered
|
|
8372
|
+
// for that to work, since components will use the WatcherContext.
|
|
8373
|
+
await serviceContainer.addServiceAsync(WatcherServiceDefinition);
|
|
8053
8374
|
// Register the shell service (top level toolbar/side pane UI layout).
|
|
8054
8375
|
await serviceContainer.addServiceAsync(MakeShellServiceDefinition(options));
|
|
8055
|
-
// Register a service that simply consumes the
|
|
8376
|
+
// Register a service that simply consumes the services we need before first render.
|
|
8056
8377
|
await serviceContainer.addServiceAsync({
|
|
8057
|
-
friendlyName: "
|
|
8058
|
-
consumes: [RootComponentServiceIdentity],
|
|
8059
|
-
factory: (rootComponentService) => {
|
|
8378
|
+
friendlyName: "Service Bootstrapper",
|
|
8379
|
+
consumes: [RootComponentServiceIdentity, WatcherServiceIdentity],
|
|
8380
|
+
factory: (rootComponentService, watcherService) => {
|
|
8060
8381
|
// Use function syntax for the state setter since the root component may be a function component.
|
|
8061
|
-
|
|
8382
|
+
setBootstrapServices({ rootComponentService, watcherService });
|
|
8062
8383
|
return {
|
|
8063
|
-
dispose: () =>
|
|
8384
|
+
dispose: () => setBootstrapServices(undefined),
|
|
8064
8385
|
};
|
|
8065
8386
|
},
|
|
8066
8387
|
});
|
|
@@ -8072,7 +8393,7 @@ function MakeModularTool(options) {
|
|
|
8072
8393
|
}
|
|
8073
8394
|
// Register the extension list service (for browsing/installing extensions) if extension feeds are provided.
|
|
8074
8395
|
if (extensionFeeds.length > 0) {
|
|
8075
|
-
const { ExtensionListServiceDefinition } = await import('./extensionsListService-
|
|
8396
|
+
const { ExtensionListServiceDefinition } = await import('./extensionsListService-CAOSDkIg.js');
|
|
8076
8397
|
await serviceContainer.addServiceAsync(ExtensionListServiceDefinition);
|
|
8077
8398
|
}
|
|
8078
8399
|
// Register all external services (that make up a unique tool).
|
|
@@ -8139,12 +8460,17 @@ function MakeModularTool(options) {
|
|
|
8139
8460
|
setExtensionInstallError(undefined);
|
|
8140
8461
|
}, [setExtensionInstallError]);
|
|
8141
8462
|
// Show a spinner until a main view has been set.
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8463
|
+
if (!bootstrapServices) {
|
|
8464
|
+
return (jsx(SettingsStoreContext.Provider, { value: settingsStore, children: jsx(Theme, { className: classes.app, children: jsx(Spinner, { className: classes.spinner }) }) }));
|
|
8465
|
+
}
|
|
8466
|
+
else {
|
|
8467
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8468
|
+
const Content = bootstrapServices.rootComponentService.rootComponent;
|
|
8469
|
+
return (
|
|
8470
|
+
// Expose the settings store as a React context so that UI components can read/write
|
|
8471
|
+
// settings without the ISettingsService needing to be explicitly passed around.
|
|
8472
|
+
jsx(SettingsStoreContext.Provider, { value: settingsStore, children: jsx(WatcherContext.Provider, { value: bootstrapServices.watcherService, children: jsx(ExtensionManagerContext.Provider, { value: extensionManagerContext, children: jsx(Theme, { className: classes.app, children: jsxs(ToastProvider, { children: [jsx(Dialog, { open: !!requiredExtensions, modalType: "alert", children: jsx(DialogSurface, { children: jsxs(DialogBody, { children: [jsx(DialogTitle, { children: "Required Extensions" }), jsxs(DialogContent, { children: ["Opening this URL requires the following extensions to be installed and enabled:", jsx("ul", { children: requiredExtensions?.map((name) => jsx("li", { children: name }, name)) })] }), jsxs(DialogActions, { children: [jsx(Button$1, { appearance: "primary", onClick: onAcceptRequiredExtensions, children: "Install & Enable" }), jsx(Button$1, { appearance: "secondary", onClick: onRejectRequiredExtensions, children: "No Thanks" })] })] }) }) }), jsx(Dialog, { open: !!extensionInstallError, modalType: "alert", children: jsx(DialogSurface, { children: jsxs(DialogBody, { children: [jsx(DialogTitle, { children: jsxs("div", { className: classes.extensionErrorTitleDiv, children: ["Extension Install Error", jsx(ErrorCircleRegular, { className: classes.extensionErrorIcon })] }) }), jsx(DialogContent, { children: jsxs(List$1, { children: [jsx(ListItem, { children: jsx(Body1, { children: `Extension "${extensionInstallError?.extension.name}" failed to install and was removed.` }) }), jsx(ListItem, { children: jsx(Body1, { children: `${extensionInstallError?.error}` }) })] }) }), jsx(DialogActions, { children: jsx(Button$1, { appearance: "primary", onClick: onAcknowledgedExtensionInstallError, children: "Close" }) })] }) }) }), jsx(Suspense, { fallback: jsx(Spinner, { className: classes.spinner }), children: jsx(Content, {}) })] }) }) }) }) }));
|
|
8473
|
+
}
|
|
8148
8474
|
};
|
|
8149
8475
|
// Set the container element to be a flex container so that the tool can be displayed properly.
|
|
8150
8476
|
const originalContainerElementDisplay = containerElement.style.display;
|
|
@@ -8223,12 +8549,103 @@ const GizmoToolbarServiceDefinition = {
|
|
|
8223
8549
|
key: "Gizmo Toolbar",
|
|
8224
8550
|
verticalLocation: "top",
|
|
8225
8551
|
horizontalLocation: "left",
|
|
8226
|
-
|
|
8552
|
+
teachingMoment: false,
|
|
8227
8553
|
component: () => jsx(GizmoToolbar, { gizmoService: gizmoService, sceneContext: sceneContext }),
|
|
8228
8554
|
});
|
|
8229
8555
|
},
|
|
8230
8556
|
};
|
|
8231
8557
|
|
|
8558
|
+
const HighlightSelectedEntitySettingDescriptor = {
|
|
8559
|
+
key: "HighlightSelectedEntity",
|
|
8560
|
+
defaultValue: true,
|
|
8561
|
+
};
|
|
8562
|
+
const HighlightServiceDefinition = {
|
|
8563
|
+
friendlyName: "Highlight Service",
|
|
8564
|
+
consumes: [SelectionServiceIdentity, SceneContextIdentity, SettingsStoreIdentity, ThemeServiceIdentity, GizmoServiceIdentity],
|
|
8565
|
+
factory: (selectionService, sceneContext, settingsStore, themeService, gizmoService) => {
|
|
8566
|
+
let outlineLayer = null;
|
|
8567
|
+
let utilityLayer = null;
|
|
8568
|
+
let currentScene = null;
|
|
8569
|
+
let activeCameraObserver = null;
|
|
8570
|
+
function disposeOutlineLayer() {
|
|
8571
|
+
outlineLayer?.dispose();
|
|
8572
|
+
outlineLayer = null;
|
|
8573
|
+
utilityLayer?.dispose();
|
|
8574
|
+
utilityLayer = null;
|
|
8575
|
+
currentScene = null;
|
|
8576
|
+
}
|
|
8577
|
+
function getOrCreateOutlineLayer(scene) {
|
|
8578
|
+
if (!outlineLayer || currentScene !== scene) {
|
|
8579
|
+
disposeOutlineLayer();
|
|
8580
|
+
utilityLayer = gizmoService.getUtilityLayer(scene);
|
|
8581
|
+
outlineLayer = new SelectionOutlineLayer("InspectorSelectionOutline", utilityLayer.value.utilityLayerScene);
|
|
8582
|
+
updateColor(outlineLayer);
|
|
8583
|
+
currentScene = scene;
|
|
8584
|
+
}
|
|
8585
|
+
return outlineLayer;
|
|
8586
|
+
}
|
|
8587
|
+
function updateColor(outlineLayer) {
|
|
8588
|
+
outlineLayer.outlineColor = Color3.FromHexString(themeService.theme.colorBrandForeground1);
|
|
8589
|
+
}
|
|
8590
|
+
function updateHighlight() {
|
|
8591
|
+
const scene = sceneContext.currentScene;
|
|
8592
|
+
const entity = selectionService.selectedEntity instanceof AbstractMesh && !(selectionService.selectedEntity instanceof GaussianSplattingMesh)
|
|
8593
|
+
? selectionService.selectedEntity
|
|
8594
|
+
: null;
|
|
8595
|
+
if (!entity || !settingsStore.readSetting(HighlightSelectedEntitySettingDescriptor) || !scene || !scene.activeCamera) {
|
|
8596
|
+
disposeOutlineLayer();
|
|
8597
|
+
return;
|
|
8598
|
+
}
|
|
8599
|
+
const layer = getOrCreateOutlineLayer(scene);
|
|
8600
|
+
layer.clearSelection();
|
|
8601
|
+
layer.addSelection(entity);
|
|
8602
|
+
}
|
|
8603
|
+
function watchActiveCamera(scene) {
|
|
8604
|
+
activeCameraObserver?.remove();
|
|
8605
|
+
activeCameraObserver = null;
|
|
8606
|
+
if (scene) {
|
|
8607
|
+
activeCameraObserver = scene.onActiveCameraChanged.add(updateHighlight);
|
|
8608
|
+
}
|
|
8609
|
+
}
|
|
8610
|
+
// React to theme changes.
|
|
8611
|
+
const themeObserver = themeService.onChanged.add(() => {
|
|
8612
|
+
if (outlineLayer) {
|
|
8613
|
+
updateColor(outlineLayer);
|
|
8614
|
+
}
|
|
8615
|
+
});
|
|
8616
|
+
// React to selection changes.
|
|
8617
|
+
const selectionObserver = selectionService.onSelectedEntityChanged.add(updateHighlight);
|
|
8618
|
+
// React to scene changes.
|
|
8619
|
+
const sceneObserver = sceneContext.currentSceneObservable.add(() => {
|
|
8620
|
+
// Dispose the old layer when the scene changes.
|
|
8621
|
+
disposeOutlineLayer();
|
|
8622
|
+
watchActiveCamera(sceneContext.currentScene);
|
|
8623
|
+
updateHighlight();
|
|
8624
|
+
});
|
|
8625
|
+
// React to setting changes.
|
|
8626
|
+
const settingObserver = settingsStore.onChanged.add((setting) => {
|
|
8627
|
+
if (setting === HighlightSelectedEntitySettingDescriptor.key) {
|
|
8628
|
+
updateHighlight();
|
|
8629
|
+
}
|
|
8630
|
+
});
|
|
8631
|
+
// Watch active camera on the initial scene.
|
|
8632
|
+
watchActiveCamera(sceneContext.currentScene);
|
|
8633
|
+
// Initial update.
|
|
8634
|
+
updateHighlight();
|
|
8635
|
+
return {
|
|
8636
|
+
dispose: () => {
|
|
8637
|
+
themeObserver.remove();
|
|
8638
|
+
selectionObserver.remove();
|
|
8639
|
+
sceneObserver.remove();
|
|
8640
|
+
settingObserver.remove();
|
|
8641
|
+
activeCameraObserver?.remove();
|
|
8642
|
+
activeCameraObserver = null;
|
|
8643
|
+
disposeOutlineLayer();
|
|
8644
|
+
},
|
|
8645
|
+
};
|
|
8646
|
+
},
|
|
8647
|
+
};
|
|
8648
|
+
|
|
8232
8649
|
const useStyles$B = makeStyles({
|
|
8233
8650
|
badge: {
|
|
8234
8651
|
margin: tokens.spacingHorizontalXXS,
|
|
@@ -8243,7 +8660,8 @@ const MiniStatsServiceDefinition = {
|
|
|
8243
8660
|
key: "Mini Stats",
|
|
8244
8661
|
verticalLocation: "bottom",
|
|
8245
8662
|
horizontalLocation: "right",
|
|
8246
|
-
|
|
8663
|
+
order: 300 /* DefaultToolbarItemOrder.FrameRate */,
|
|
8664
|
+
teachingMoment: false,
|
|
8247
8665
|
component: () => {
|
|
8248
8666
|
const classes = useStyles$B();
|
|
8249
8667
|
const scene = useObservableState(useCallback(() => sceneContext.currentScene, [sceneContext.currentScene]), sceneContext.currentSceneObservable);
|
|
@@ -12429,7 +12847,7 @@ const SoundCommandProperties = (props) => {
|
|
|
12429
12847
|
else {
|
|
12430
12848
|
sound.play();
|
|
12431
12849
|
}
|
|
12432
|
-
} }), jsx(Property, { component:
|
|
12850
|
+
} }), jsx(Property, { component: NumberInputPropertyLine, label: "Volume", functionPath: "setVolume", value: volume, min: 0, step: 0.1, onChange: (value) => {
|
|
12433
12851
|
sound.setVolume(value);
|
|
12434
12852
|
} }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Loop", target: sound, propertyKey: "loop" })] }));
|
|
12435
12853
|
};
|
|
@@ -12469,7 +12887,7 @@ const ArcRotateCameraTransformProperties = (props) => {
|
|
|
12469
12887
|
const upperBetaLimit = useProperty(camera, "upperBetaLimit") ?? Math.PI;
|
|
12470
12888
|
const lowerRadiusLimit = useProperty(camera, "lowerRadiusLimit");
|
|
12471
12889
|
const upperRadiusLimit = useProperty(camera, "upperRadiusLimit");
|
|
12472
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component:
|
|
12890
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Alpha", description: `Horizontal angle in ${useDegrees ? "degrees" : "radians"}`, target: camera, propertyKey: "alpha", min: toDisplayAngle(lowerAlphaLimit), max: toDisplayAngle(upperAlphaLimit), step: toDisplayAngle(0.01), unit: useDegrees ? "°" : "rad", convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Beta", description: `Vertical angle in ${useDegrees ? "degrees" : "radians"}`, target: camera, propertyKey: "beta", min: toDisplayAngle(lowerBetaLimit), max: toDisplayAngle(upperBetaLimit), step: toDisplayAngle(0.01), unit: useDegrees ? "°" : "rad", convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius", description: "Distance from the target point.", target: camera, propertyKey: "radius", min: lowerRadiusLimit ?? undefined, max: upperRadiusLimit ?? undefined, step: 0.01 })] }));
|
|
12473
12891
|
};
|
|
12474
12892
|
const ArcRotateCameraControlProperties = (props) => {
|
|
12475
12893
|
const { camera } = props;
|
|
@@ -12481,8 +12899,19 @@ const ArcRotateCameraCollisionProperties = (props) => {
|
|
|
12481
12899
|
};
|
|
12482
12900
|
const ArcRotateCameraLimitsProperties = (props) => {
|
|
12483
12901
|
const { camera } = props;
|
|
12902
|
+
const [toDisplayAngle, fromDisplayAngle, useDegrees] = useAngleConverters();
|
|
12903
|
+
const minAlphaLimit = 0;
|
|
12904
|
+
const maxAlphaLimit = Math.PI * 2;
|
|
12905
|
+
const minBetaLimit = -Math.PI;
|
|
12906
|
+
const maxBetaLimit = Math.PI;
|
|
12907
|
+
const lowerAlphaLimit = useProperty(camera, "lowerAlphaLimit") ?? minAlphaLimit;
|
|
12908
|
+
const upperAlphaLimit = useProperty(camera, "upperAlphaLimit") ?? maxAlphaLimit;
|
|
12909
|
+
const lowerBetaLimit = useProperty(camera, "lowerBetaLimit") ?? minBetaLimit;
|
|
12910
|
+
const upperBetaLimit = useProperty(camera, "upperBetaLimit") ?? maxBetaLimit;
|
|
12911
|
+
const lowerRadiusLimit = useProperty(camera, "lowerRadiusLimit");
|
|
12912
|
+
const upperRadiusLimit = useProperty(camera, "upperRadiusLimit");
|
|
12484
12913
|
// TODO-Iv2: Update defaultValues
|
|
12485
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Lower Alpha Limit", target: camera, propertyKey: "lowerAlphaLimit", nullable: true, defaultValue:
|
|
12914
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Lower Alpha Limit", target: camera, propertyKey: "lowerAlphaLimit", nullable: true, defaultValue: toDisplayAngle(minAlphaLimit), min: toDisplayAngle(minAlphaLimit), max: toDisplayAngle(upperAlphaLimit), unit: useDegrees ? "°" : "rad", convertTo: (value) => (value === null ? value : toDisplayAngle(value, true)), convertFrom: (value) => (value === null ? value : fromDisplayAngle(value)) }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Upper Alpha Limit", target: camera, propertyKey: "upperAlphaLimit", nullable: true, defaultValue: toDisplayAngle(maxAlphaLimit), min: toDisplayAngle(lowerAlphaLimit), max: toDisplayAngle(maxAlphaLimit), unit: useDegrees ? "°" : "rad", convertTo: (value) => (value === null ? value : toDisplayAngle(value, true)), convertFrom: (value) => (value === null ? value : fromDisplayAngle(value)) }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Lower Beta Limit", target: camera, propertyKey: "lowerBetaLimit", nullable: true, defaultValue: toDisplayAngle(minBetaLimit), min: toDisplayAngle(minBetaLimit), max: toDisplayAngle(upperBetaLimit), unit: useDegrees ? "°" : "rad", convertTo: (value) => (value === null ? value : toDisplayAngle(value, true)), convertFrom: (value) => (value === null ? value : fromDisplayAngle(value)) }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Upper Beta Limit", target: camera, propertyKey: "upperBetaLimit", nullable: true, defaultValue: toDisplayAngle(maxBetaLimit), min: toDisplayAngle(lowerBetaLimit), max: toDisplayAngle(maxBetaLimit), unit: useDegrees ? "°" : "rad", convertTo: (value) => (value === null ? value : toDisplayAngle(value, true)), convertFrom: (value) => (value === null ? value : fromDisplayAngle(value)) }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Lower Radius Limit", target: camera, propertyKey: "lowerRadiusLimit", nullable: true, defaultValue: 0, min: 0, max: upperRadiusLimit ?? undefined }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Upper Radius Limit", target: camera, propertyKey: "upperRadiusLimit", nullable: true, defaultValue: 100, min: lowerRadiusLimit ?? undefined }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Lower Target Y Limit", target: camera, propertyKey: "lowerTargetYLimit" })] }));
|
|
12486
12915
|
};
|
|
12487
12916
|
const ArcRotateCameraBehaviorsProperties = (props) => {
|
|
12488
12917
|
const { camera } = props;
|
|
@@ -12499,7 +12928,7 @@ const GeospatialCameraTransformProperties = (props) => {
|
|
|
12499
12928
|
const pitchMax = limits?.pitchMax ?? Math.PI / 2;
|
|
12500
12929
|
const radiusMin = limits?.radiusMin ?? 0;
|
|
12501
12930
|
const radiusMax = limits?.radiusMax ?? Infinity;
|
|
12502
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component:
|
|
12931
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Yaw", description: `Horizontal rotation in ${useDegrees ? "degrees" : "radians"} (0 = north)`, target: camera, propertyKey: "yaw", min: toDisplayAngle(yawMin), max: toDisplayAngle(yawMax), step: toDisplayAngle(0.01), unit: useDegrees ? "°" : "rad", convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Pitch", description: `Vertical angle in ${useDegrees ? "degrees" : "radians"} (0 = looking down, π/2 = horizon)`, target: camera, propertyKey: "pitch", min: toDisplayAngle(pitchMin), max: toDisplayAngle(pitchMax), step: toDisplayAngle(0.01), unit: useDegrees ? "°" : "rad", convertTo: (value) => toDisplayAngle(value, true), convertFrom: fromDisplayAngle }), radiusMax !== Infinity ? (jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Radius", description: "Distance from the center point.", target: camera, propertyKey: "radius", min: radiusMin, max: radiusMax, step: 0.01 })) : (jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius", description: "Distance from the center point.", target: camera, propertyKey: "radius", min: 0, step: 0.01 })), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Center", description: "The point on the globe the camera orbits around.", target: camera, propertyKey: "center" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Position", description: "The camera's position.", target: camera, propertyKey: "position" })] }));
|
|
12503
12932
|
};
|
|
12504
12933
|
const GeospatialCameraCollisionProperties = (props) => {
|
|
12505
12934
|
const { camera } = props;
|
|
@@ -12576,7 +13005,7 @@ const CameraGeneralProperties = (props) => {
|
|
|
12576
13005
|
const { camera } = props;
|
|
12577
13006
|
const [toDisplayAngle, fromDisplayAngle, useDegrees] = useAngleConverters();
|
|
12578
13007
|
const mode = useProperty(camera, "mode");
|
|
12579
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Near Plane", description: "Anything closer than this will not be drawn.", target: camera, propertyKey: "minZ" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Far Plane", description: "Anything further than this will not be drawn.", target: camera, propertyKey: "maxZ" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Inertia", target: camera, propertyKey: "inertia", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: HexPropertyLine, label: "Layer Mask", target: camera, propertyKey: "layerMask" }), jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Mode", options: CameraModes, target: camera, propertyKey: "mode" }), jsx(Collapse, { visible: mode === Camera.PERSPECTIVE_CAMERA, children: jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "FOV", description: `Field of view in ${useDegrees ? "degrees" : "radians"}`, target: camera, propertyKey: "fov", min: toDisplayAngle(0.1), max: toDisplayAngle(Math.PI), step: toDisplayAngle(0.01), convertTo: toDisplayAngle, convertFrom: fromDisplayAngle }) }), jsx(Collapse, { visible: mode === Camera.ORTHOGRAPHIC_CAMERA, children: jsxs("div", { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Left", target: camera, step: 0.1, propertyKey: "orthoLeft", nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Right", target: camera, step: 0.1, propertyKey: "orthoRight", nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Top", target: camera, step: 0.1, propertyKey: "orthoTop", nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Bottom", target: camera, step: 0.1, propertyKey: "orthoBottom", nullable: true, defaultValue: 0 })] }) })] }));
|
|
13008
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Near Plane", description: "Anything closer than this will not be drawn.", target: camera, propertyKey: "minZ" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Far Plane", description: "Anything further than this will not be drawn.", target: camera, propertyKey: "maxZ" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Inertia", target: camera, propertyKey: "inertia", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: HexPropertyLine, label: "Layer Mask", target: camera, propertyKey: "layerMask" }), jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Mode", options: CameraModes, target: camera, propertyKey: "mode" }), jsx(Collapse, { visible: mode === Camera.PERSPECTIVE_CAMERA, children: jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "FOV", description: `Field of view in ${useDegrees ? "degrees" : "radians"}`, target: camera, propertyKey: "fov", min: toDisplayAngle(0.1), max: toDisplayAngle(Math.PI), step: toDisplayAngle(0.01), unit: useDegrees ? "°" : "rad", convertTo: toDisplayAngle, convertFrom: fromDisplayAngle }) }), jsx(Collapse, { visible: mode === Camera.ORTHOGRAPHIC_CAMERA, children: jsxs("div", { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Left", target: camera, step: 0.1, propertyKey: "orthoLeft", nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Right", target: camera, step: 0.1, propertyKey: "orthoRight", nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Top", target: camera, step: 0.1, propertyKey: "orthoTop", nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Bottom", target: camera, step: 0.1, propertyKey: "orthoBottom", nullable: true, defaultValue: 0 })] }) })] }));
|
|
12580
13009
|
};
|
|
12581
13010
|
|
|
12582
13011
|
const FollowCameraTransformProperties = (props) => {
|
|
@@ -13012,7 +13441,7 @@ const ShadowsSetupProperties = ({ context: shadowLight }) => {
|
|
|
13012
13441
|
};
|
|
13013
13442
|
|
|
13014
13443
|
const SpotLightSetupProperties = ({ context: spotLight }) => {
|
|
13015
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { label: "Diffuse", component: Color3PropertyLine, target: spotLight, propertyKey: "diffuse" }), jsx(BoundProperty, { label: "Specular", component: Color3PropertyLine, target: spotLight, propertyKey: "specular" }), jsx(BoundProperty, { label: "Direction", component: Vector3PropertyLine, target: spotLight, propertyKey: "direction" }), jsx(BoundProperty, { label: "Position", component: Vector3PropertyLine, target: spotLight, propertyKey: "position" }), jsx(BoundProperty, { label: "Angle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "angle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "InnerAngle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "innerAngle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "Exponent", component: NumberInputPropertyLine, target: spotLight, propertyKey: "exponent" })] }));
|
|
13444
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { label: "Diffuse", component: Color3PropertyLine, target: spotLight, propertyKey: "diffuse" }), jsx(BoundProperty, { label: "Specular", component: Color3PropertyLine, target: spotLight, propertyKey: "specular" }), jsx(BoundProperty, { label: "Direction", component: Vector3PropertyLine, target: spotLight, propertyKey: "direction" }), jsx(BoundProperty, { label: "Position", component: Vector3PropertyLine, target: spotLight, propertyKey: "position" }), jsx(BoundProperty, { label: "Angle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "angle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "InnerAngle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "innerAngle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "Intensity", component: NumberInputPropertyLine, target: spotLight, propertyKey: "intensity" }), jsx(BoundProperty, { label: "Exponent", component: NumberInputPropertyLine, target: spotLight, propertyKey: "exponent" })] }));
|
|
13016
13445
|
};
|
|
13017
13446
|
|
|
13018
13447
|
const LightPropertiesServiceDefinition = {
|
|
@@ -13295,7 +13724,7 @@ const Gradient = (props) => {
|
|
|
13295
13724
|
// Only use compact mode when there are numeric values (spinbuttons) taking up space
|
|
13296
13725
|
const hasNumericValues = !(gradient.value1 instanceof Color3 || gradient.value1 instanceof Color4) ||
|
|
13297
13726
|
(gradient.value2 !== undefined && !(gradient.value2 instanceof Color3 || gradient.value2 instanceof Color4));
|
|
13298
|
-
return (jsxs("div", { id: "gradientContainer", className: classes.container, children: [jsx("div", { className: gradient.value1 instanceof Color3 || gradient.value1 instanceof Color4 ? classes.colorWrapper : classes.valueWrapper, children: gradient.value1 instanceof Color3 || gradient.value1 instanceof Color4 ? (jsx(ColorPickerPopup, { value: gradient.value1, onChange: (color) => gradientChange({ ...gradient, value1: color }) })) : (jsx(SyncedSliderInput, { step: 0.01, value: gradient.value1, onChange: (val) => gradientChange({ ...gradient, value1: val }), compact: true })) }), gradient.value2 !== undefined && (jsx("div", { className: gradient.value2 instanceof Color3 || gradient.value2 instanceof Color4 ? classes.colorWrapper : classes.valueWrapper, children: gradient.value2 instanceof Color3 || gradient.value2 instanceof Color4 ? (jsx(ColorPickerPopup, { value: gradient.value2, onChange: (color) => gradientChange({ ...gradient, value2: color }) })) : (jsx(SyncedSliderInput, { step: 0.01, value: gradient.value2, onChange: (val) => gradientChange({ ...gradient, value2: val }), compact: true })) })), jsx("div", { className: classes.stepSliderWrapper, children: jsx(SyncedSliderInput, { notifyOnlyOnRelease: true, min: 0, max: 1, step: 0.01, value: gradient.step, onChange: (val) => gradientChange({ ...gradient, step: val }), compact: hasNumericValues, growSlider: !hasNumericValues }) })] }));
|
|
13727
|
+
return (jsxs("div", { id: "gradientContainer", className: classes.container, children: [jsx("div", { className: gradient.value1 instanceof Color3 || gradient.value1 instanceof Color4 ? classes.colorWrapper : classes.valueWrapper, children: gradient.value1 instanceof Color3 || gradient.value1 instanceof Color4 ? (jsx(ColorPickerPopup, { value: gradient.value1, onChange: (color) => gradientChange({ ...gradient, value1: color }) })) : (jsx(SyncedSliderInput, { step: 0.01, precision: 2, value: gradient.value1, onChange: (val) => gradientChange({ ...gradient, value1: val }), compact: true })) }), gradient.value2 !== undefined && (jsx("div", { className: gradient.value2 instanceof Color3 || gradient.value2 instanceof Color4 ? classes.colorWrapper : classes.valueWrapper, children: gradient.value2 instanceof Color3 || gradient.value2 instanceof Color4 ? (jsx(ColorPickerPopup, { value: gradient.value2, onChange: (color) => gradientChange({ ...gradient, value2: color }) })) : (jsx(SyncedSliderInput, { step: 0.01, precision: 2, value: gradient.value2, onChange: (val) => gradientChange({ ...gradient, value2: val }), compact: true })) })), jsx("div", { className: classes.stepSliderWrapper, children: jsx(SyncedSliderInput, { notifyOnlyOnRelease: true, min: 0, max: 1, step: 0.01, precision: 2, value: gradient.step, onChange: (val) => gradientChange({ ...gradient, step: val }), compact: hasNumericValues, growSlider: !hasNumericValues }) })] }));
|
|
13299
13728
|
};
|
|
13300
13729
|
const FactorGradientCast = Gradient;
|
|
13301
13730
|
const Color3GradientCast = Gradient;
|
|
@@ -13771,25 +14200,6 @@ const ComboBox = forwardRef((props, ref) => {
|
|
|
13771
14200
|
return (jsxs("div", { className: styles.root, children: [jsx("label", { id: comboId, children: props.label }), jsx(Combobox, { ref: ref, defaultOpen: props.defaultOpen, size: size, root: { className: styles.comboBox }, input: { className: styles.input }, listbox: { className: styles.listbox }, onOptionSelect: onOptionSelect, "aria-labelledby": comboId, placeholder: "Search..", onChange: (ev) => setQuery(ev.target.value), value: query, children: children })] }));
|
|
13772
14201
|
});
|
|
13773
14202
|
|
|
13774
|
-
/**
|
|
13775
|
-
* A hook that provides a transient state value and a "pulse" function to set it.
|
|
13776
|
-
* The transient value is meant to be consumed immediately after being set, and will be cleared on the next render.
|
|
13777
|
-
* @typeParam T The type of the transient value.
|
|
13778
|
-
* @returns A tuple containing the transient value and a function to "pulse" the state.
|
|
13779
|
-
*/
|
|
13780
|
-
function useImpulse() {
|
|
13781
|
-
const impulseRef = useRef(undefined);
|
|
13782
|
-
const [, setVersion] = useState(0);
|
|
13783
|
-
const pulse = useCallback((value) => {
|
|
13784
|
-
impulseRef.current = value;
|
|
13785
|
-
setVersion((v) => v + 1);
|
|
13786
|
-
}, []);
|
|
13787
|
-
// Consume the impulse value and clear it
|
|
13788
|
-
const value = impulseRef.current;
|
|
13789
|
-
impulseRef.current = undefined;
|
|
13790
|
-
return [value, pulse];
|
|
13791
|
-
}
|
|
13792
|
-
|
|
13793
14203
|
const useStyles$j = makeStyles({
|
|
13794
14204
|
linkDiv: {
|
|
13795
14205
|
display: "flex",
|
|
@@ -14166,7 +14576,7 @@ const PBRBaseMaterialDebugProperties = (props) => {
|
|
|
14166
14576
|
const SkyMaterialProperties = (props) => {
|
|
14167
14577
|
const { material } = props;
|
|
14168
14578
|
const [toDisplayAngle, fromDisplayAngle, useDegrees] = useAngleConverters();
|
|
14169
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component:
|
|
14579
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Azimuth", description: `Azimuth angle in ${useDegrees ? "degrees" : "radians"}`, target: material, propertyKey: "azimuth", step: toDisplayAngle(0.001), unit: useDegrees ? "°" : "rad", convertTo: toDisplayAngle, convertFrom: fromDisplayAngle, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Inclination", description: `Inclination angle in ${useDegrees ? "degrees" : "radians"}`, target: material, propertyKey: "inclination", min: toDisplayAngle(0), max: toDisplayAngle(Math.PI / 2), step: toDisplayAngle(0.001), unit: useDegrees ? "°" : "rad", convertTo: toDisplayAngle, convertFrom: fromDisplayAngle, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Turbidity", description: "Atmospheric turbidity.", target: material, propertyKey: "turbidity", min: 0, max: 100, step: 0.1, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Luminance", description: "Brightness of the sky (0 to 1).", target: material, propertyKey: "luminance", min: 0, max: 1, step: 0.001, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Rayleigh", description: "Rayleigh scattering coefficient (0 to 4).", target: material, propertyKey: "rayleigh", min: 0, max: 4, step: 0.001, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Mie Directional G", description: "Mie directional scattering (0 to 1).", target: material, propertyKey: "mieDirectionalG", min: 0, max: 1, step: 0.001, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Mie Coefficient", description: "Mie scattering coefficient (0 to 1).", target: material, propertyKey: "mieCoefficient", min: 0, max: 1, step: 0.001, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Distance", description: "Distance to the sky dome (0 to 1000 units).", target: material, propertyKey: "distance", min: 0, max: 1000, step: 0.1, docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Sun Pos", description: "Enable custom sun position.", target: material, propertyKey: "useSunPosition", docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Sun Position", description: "Custom sun position (Vector3).", target: material, propertyKey: "sunPosition", docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#configuring-the-sky-material" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Camera Offset", description: "Offset for the camera (Vector3).", target: material, propertyKey: "cameraOffset", docLink: "https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/skyMat/#keeping-the-horizon-relative-to-the-camera-elevation" })] }));
|
|
14170
14580
|
};
|
|
14171
14581
|
|
|
14172
14582
|
const StandardMaterialGeneralProperties = (props) => {
|
|
@@ -14336,35 +14746,35 @@ const MaterialPropertiesServiceDefinition = {
|
|
|
14336
14746
|
predicate: (entity) => entity instanceof OpenPBRMaterial,
|
|
14337
14747
|
content: [
|
|
14338
14748
|
{
|
|
14339
|
-
section: "
|
|
14749
|
+
section: "OpenPBR",
|
|
14340
14750
|
component: ({ context }) => jsx(OpenPBRMaterialBaseProperties, { material: context }),
|
|
14341
14751
|
},
|
|
14342
14752
|
{
|
|
14343
|
-
section: "
|
|
14753
|
+
section: "OpenPBR",
|
|
14344
14754
|
component: ({ context }) => jsx(OpenPBRMaterialSpecularProperties, { material: context }),
|
|
14345
14755
|
},
|
|
14346
14756
|
{
|
|
14347
|
-
section: "
|
|
14757
|
+
section: "OpenPBR",
|
|
14348
14758
|
component: ({ context }) => jsx(OpenPBRMaterialTransmissionProperties, { material: context }),
|
|
14349
14759
|
},
|
|
14350
14760
|
{
|
|
14351
|
-
section: "
|
|
14761
|
+
section: "OpenPBR",
|
|
14352
14762
|
component: ({ context }) => jsx(OpenPBRMaterialCoatProperties, { material: context }),
|
|
14353
14763
|
},
|
|
14354
14764
|
{
|
|
14355
|
-
section: "
|
|
14765
|
+
section: "OpenPBR",
|
|
14356
14766
|
component: ({ context }) => jsx(OpenPBRMaterialFuzzProperties, { material: context }),
|
|
14357
14767
|
},
|
|
14358
14768
|
{
|
|
14359
|
-
section: "
|
|
14769
|
+
section: "OpenPBR",
|
|
14360
14770
|
component: ({ context }) => jsx(OpenPBRMaterialEmissionProperties, { material: context }),
|
|
14361
14771
|
},
|
|
14362
14772
|
{
|
|
14363
|
-
section: "
|
|
14773
|
+
section: "OpenPBR",
|
|
14364
14774
|
component: ({ context }) => jsx(OpenPBRMaterialThinFilmProperties, { material: context }),
|
|
14365
14775
|
},
|
|
14366
14776
|
{
|
|
14367
|
-
section: "
|
|
14777
|
+
section: "OpenPBR",
|
|
14368
14778
|
component: ({ context }) => jsx(OpenPBRMaterialGeometryProperties, { material: context }),
|
|
14369
14779
|
},
|
|
14370
14780
|
],
|
|
@@ -17336,7 +17746,7 @@ const SpriteGeneralProperties = (props) => {
|
|
|
17336
17746
|
const SpriteTransformProperties = (props) => {
|
|
17337
17747
|
const { sprite } = props;
|
|
17338
17748
|
const [toDisplayAngle, fromDisplayAngle, useDegrees] = useAngleConverters();
|
|
17339
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Vector3PropertyLine, label: "Position", target: sprite, propertyKey: "position" }), jsx(BoundProperty, { component:
|
|
17749
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Vector3PropertyLine, label: "Position", target: sprite, propertyKey: "position" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Angle", description: `Rotation angle of the sprite in ${useDegrees ? "degrees" : "radians"}`, step: toDisplayAngle(0.01), unit: useDegrees ? "°" : "rad", target: sprite, propertyKey: "angle", convertTo: toDisplayAngle, convertFrom: fromDisplayAngle }, "Angle"), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Width", description: "Width of the sprite (in world space units)", target: sprite, propertyKey: "width" }, "Width"), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Height", description: "Height of the sprite (in world space units)", target: sprite, propertyKey: "height" }, "Height")] }));
|
|
17340
17750
|
};
|
|
17341
17751
|
const SpriteAnimationProperties = (props) => {
|
|
17342
17752
|
const { sprite } = props;
|
|
@@ -18930,7 +19340,7 @@ const Contrast = {
|
|
|
18930
19340
|
const handleExposureChange = (_, data) => {
|
|
18931
19341
|
setExposure(data.value);
|
|
18932
19342
|
};
|
|
18933
|
-
return (jsxs("div", { className: classes.settingsContainer, children: [jsxs("div", { className: classes.sliderRow, children: [jsxs(Label, { children: ["Contrast: ", contrast] }), jsx(Slider, { min: -100, max: 100, value: contrast, onChange: handleContrastChange })] }), jsxs("div", { className: classes.sliderRow, children: [jsxs(Label, { children: ["Exposure: ", exposure] }), jsx(Slider, { min: -100, max: 100, value: exposure, onChange: handleExposureChange })] })] }));
|
|
19343
|
+
return (jsxs("div", { className: classes.settingsContainer, children: [jsxs("div", { className: classes.sliderRow, children: [jsxs(Label, { children: ["Contrast: ", contrast] }), jsx(Slider$1, { min: -100, max: 100, value: contrast, onChange: handleContrastChange })] }), jsxs("div", { className: classes.sliderRow, children: [jsxs(Label, { children: ["Exposure: ", exposure] }), jsx(Slider$1, { min: -100, max: 100, value: exposure, onChange: handleExposureChange })] })] }));
|
|
18934
19344
|
},
|
|
18935
19345
|
};
|
|
18936
19346
|
},
|
|
@@ -19152,7 +19562,7 @@ const Paintbrush = {
|
|
|
19152
19562
|
const handleWidthChange = (_, data) => {
|
|
19153
19563
|
setWidth(data.value);
|
|
19154
19564
|
};
|
|
19155
|
-
return (jsx("div", { className: classes.settingsContainer, children: jsxs("div", { className: classes.sliderRow, children: [jsxs(Label, { children: ["Size: ", width] }), jsx(Slider, { min: 1, max: 100, value: width, onChange: handleWidthChange })] }) }));
|
|
19565
|
+
return (jsx("div", { className: classes.settingsContainer, children: jsxs("div", { className: classes.sliderRow, children: [jsxs(Label, { children: ["Size: ", width] }), jsx(Slider$1, { min: 1, max: 100, value: width, onChange: handleWidthChange })] }) }));
|
|
19156
19566
|
},
|
|
19157
19567
|
};
|
|
19158
19568
|
},
|
|
@@ -19397,7 +19807,7 @@ const TransformProperties = (props) => {
|
|
|
19397
19807
|
const quatRotation = useQuaternionProperty(transform, "rotationQuaternion");
|
|
19398
19808
|
const [useDegrees] = useSetting(UseDegreesSettingDescriptor);
|
|
19399
19809
|
const [useEuler] = useSetting(UseEulerSettingDescriptor);
|
|
19400
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Vector3PropertyLine, label: "Position", target: transform, propertyKey: "position" }), quatRotation ? (jsx(Property, { component: QuaternionPropertyLine, label: "Rotation
|
|
19810
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Vector3PropertyLine, label: "Position", target: transform, propertyKey: "position" }), quatRotation ? (jsx(Property, { component: QuaternionPropertyLine, label: "Rotation", propertyPath: "rotationQuaternion", value: quatRotation, onChange: (val) => (transform.rotationQuaternion = val), useDegrees: useDegrees, useEuler: useEuler })) : (jsx(BoundProperty, { component: RotationVectorPropertyLine, label: "Rotation", target: transform, propertyKey: "rotation", useDegrees: useDegrees })), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Scaling", target: transform, propertyKey: "scaling", step: 0.1 })] }));
|
|
19401
19811
|
};
|
|
19402
19812
|
|
|
19403
19813
|
const TransformPropertiesServiceDefinition = {
|
|
@@ -19425,8 +19835,8 @@ const TransformPropertiesServiceDefinition = {
|
|
|
19425
19835
|
|
|
19426
19836
|
const AnimationGroupExplorerServiceDefinition = {
|
|
19427
19837
|
friendlyName: "Animation Group Explorer",
|
|
19428
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
19429
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
19838
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
19839
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
19430
19840
|
const scene = sceneContext.currentScene;
|
|
19431
19841
|
if (!scene) {
|
|
19432
19842
|
return undefined;
|
|
@@ -19439,11 +19849,7 @@ const AnimationGroupExplorerServiceDefinition = {
|
|
|
19439
19849
|
getEntityDisplayInfo: (entity) => {
|
|
19440
19850
|
const namedEntity = entity instanceof AnimationGroup ? entity : entity.animation;
|
|
19441
19851
|
const onChangeObservable = new Observable();
|
|
19442
|
-
const nameHookToken =
|
|
19443
|
-
afterSet: () => {
|
|
19444
|
-
onChangeObservable.notifyObservers();
|
|
19445
|
-
},
|
|
19446
|
-
});
|
|
19852
|
+
const nameHookToken = watcherService.watchProperty(namedEntity, "name", () => onChangeObservable.notifyObservers());
|
|
19447
19853
|
return {
|
|
19448
19854
|
get name() {
|
|
19449
19855
|
return namedEntity.name;
|
|
@@ -19509,8 +19915,8 @@ const AnimationGroupExplorerServiceDefinition = {
|
|
|
19509
19915
|
|
|
19510
19916
|
const AtmosphereExplorerServiceDefinition = {
|
|
19511
19917
|
friendlyName: "Atmosphere Explorer",
|
|
19512
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
19513
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
19918
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
19919
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
19514
19920
|
const scene = sceneContext.currentScene;
|
|
19515
19921
|
if (!scene) {
|
|
19516
19922
|
return undefined;
|
|
@@ -19521,11 +19927,7 @@ const AtmosphereExplorerServiceDefinition = {
|
|
|
19521
19927
|
getRootEntities: () => (scene.getExternalData("atmosphere") ? [scene.getExternalData("atmosphere")] : []),
|
|
19522
19928
|
getEntityDisplayInfo: (atmosphere) => {
|
|
19523
19929
|
const onChangeObservable = new Observable();
|
|
19524
|
-
const nameHookToken =
|
|
19525
|
-
afterSet: () => {
|
|
19526
|
-
onChangeObservable.notifyObservers();
|
|
19527
|
-
},
|
|
19528
|
-
});
|
|
19930
|
+
const nameHookToken = watcherService.watchProperty(atmosphere, "name", () => onChangeObservable.notifyObservers());
|
|
19529
19931
|
return {
|
|
19530
19932
|
get name() {
|
|
19531
19933
|
return atmosphere.name;
|
|
@@ -19584,8 +19986,8 @@ const DisposableCommandServiceDefinition = {
|
|
|
19584
19986
|
|
|
19585
19987
|
const EffectLayerExplorerServiceDefinition = {
|
|
19586
19988
|
friendlyName: "Effect Layer Explorer",
|
|
19587
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
19588
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
19989
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
19990
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
19589
19991
|
const scene = sceneContext.currentScene;
|
|
19590
19992
|
if (!scene) {
|
|
19591
19993
|
return undefined;
|
|
@@ -19596,11 +19998,7 @@ const EffectLayerExplorerServiceDefinition = {
|
|
|
19596
19998
|
getRootEntities: () => scene.effectLayers,
|
|
19597
19999
|
getEntityDisplayInfo: (effectLayer) => {
|
|
19598
20000
|
const onChangeObservable = new Observable();
|
|
19599
|
-
const nameHookToken =
|
|
19600
|
-
afterSet: () => {
|
|
19601
|
-
onChangeObservable.notifyObservers();
|
|
19602
|
-
},
|
|
19603
|
-
});
|
|
20001
|
+
const nameHookToken = watcherService.watchProperty(effectLayer, "name", () => onChangeObservable.notifyObservers());
|
|
19604
20002
|
return {
|
|
19605
20003
|
get name() {
|
|
19606
20004
|
return effectLayer.name;
|
|
@@ -19626,8 +20024,8 @@ const EffectLayerExplorerServiceDefinition = {
|
|
|
19626
20024
|
|
|
19627
20025
|
const FrameGraphExplorerServiceDefinition = {
|
|
19628
20026
|
friendlyName: "Frame Graph Explorer",
|
|
19629
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
19630
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20027
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20028
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
19631
20029
|
const scene = sceneContext.currentScene;
|
|
19632
20030
|
if (!scene) {
|
|
19633
20031
|
return undefined;
|
|
@@ -19638,11 +20036,7 @@ const FrameGraphExplorerServiceDefinition = {
|
|
|
19638
20036
|
getRootEntities: () => scene.frameGraphs,
|
|
19639
20037
|
getEntityDisplayInfo: (frameGraph) => {
|
|
19640
20038
|
const onChangeObservable = new Observable();
|
|
19641
|
-
const nameHookToken =
|
|
19642
|
-
afterSet: () => {
|
|
19643
|
-
onChangeObservable.notifyObservers();
|
|
19644
|
-
},
|
|
19645
|
-
});
|
|
20039
|
+
const nameHookToken = watcherService.watchProperty(frameGraph, "name", () => onChangeObservable.notifyObservers());
|
|
19646
20040
|
return {
|
|
19647
20041
|
get name() {
|
|
19648
20042
|
return frameGraph.name;
|
|
@@ -19663,9 +20057,7 @@ const FrameGraphExplorerServiceDefinition = {
|
|
|
19663
20057
|
order: 900 /* DefaultCommandsOrder.FrameGraphPlay */,
|
|
19664
20058
|
getCommand: (frameGraph) => {
|
|
19665
20059
|
const onChangeObservable = new Observable();
|
|
19666
|
-
const frameGraphHook =
|
|
19667
|
-
afterSet: () => onChangeObservable.notifyObservers(),
|
|
19668
|
-
});
|
|
20060
|
+
const frameGraphHook = watcherService.watchProperty(scene, "frameGraph", () => onChangeObservable.notifyObservers());
|
|
19669
20061
|
return {
|
|
19670
20062
|
type: "toggle",
|
|
19671
20063
|
displayName: "Make Active",
|
|
@@ -19728,8 +20120,8 @@ function IsControl(entity) {
|
|
|
19728
20120
|
}
|
|
19729
20121
|
const GuiExplorerServiceDefinition = {
|
|
19730
20122
|
friendlyName: "GUI Explorer",
|
|
19731
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
19732
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20123
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20124
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
19733
20125
|
const scene = sceneContext.currentScene;
|
|
19734
20126
|
if (!scene) {
|
|
19735
20127
|
return undefined;
|
|
@@ -19755,10 +20147,8 @@ const GuiExplorerServiceDefinition = {
|
|
|
19755
20147
|
const disposeActions = [];
|
|
19756
20148
|
const onChangeObservable = new Observable();
|
|
19757
20149
|
disposeActions.push(() => onChangeObservable.clear());
|
|
19758
|
-
const nameHookToken =
|
|
19759
|
-
|
|
19760
|
-
onChangeObservable.notifyObservers();
|
|
19761
|
-
},
|
|
20150
|
+
const nameHookToken = watcherService.watchProperty(entity, "name", () => {
|
|
20151
|
+
onChangeObservable.notifyObservers();
|
|
19762
20152
|
});
|
|
19763
20153
|
disposeActions.push(() => nameHookToken.dispose());
|
|
19764
20154
|
if (!IsAdvancedDynamicTexture(entity) && IsContainer(entity)) {
|
|
@@ -19815,9 +20205,7 @@ const GuiExplorerServiceDefinition = {
|
|
|
19815
20205
|
order: 1000 /* DefaultCommandsOrder.GuiHighlight */,
|
|
19816
20206
|
getCommand: (control) => {
|
|
19817
20207
|
const onChangeObservable = new Observable();
|
|
19818
|
-
const showBoundingBoxHook =
|
|
19819
|
-
afterSet: () => onChangeObservable.notifyObservers(),
|
|
19820
|
-
});
|
|
20208
|
+
const showBoundingBoxHook = watcherService.watchProperty(control, "isHighlighted", () => onChangeObservable.notifyObservers());
|
|
19821
20209
|
return {
|
|
19822
20210
|
type: "toggle",
|
|
19823
20211
|
get displayName() {
|
|
@@ -19873,8 +20261,8 @@ const GuiExplorerServiceDefinition = {
|
|
|
19873
20261
|
|
|
19874
20262
|
const MaterialExplorerServiceDefinition = {
|
|
19875
20263
|
friendlyName: "Material Explorer",
|
|
19876
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
19877
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20264
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20265
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
19878
20266
|
const scene = sceneContext.currentScene;
|
|
19879
20267
|
if (!scene) {
|
|
19880
20268
|
return undefined;
|
|
@@ -19885,11 +20273,7 @@ const MaterialExplorerServiceDefinition = {
|
|
|
19885
20273
|
getRootEntities: () => [...scene.materials, ...scene.multiMaterials],
|
|
19886
20274
|
getEntityDisplayInfo: (material) => {
|
|
19887
20275
|
const onChangeObservable = new Observable();
|
|
19888
|
-
const nameHookToken =
|
|
19889
|
-
afterSet: () => {
|
|
19890
|
-
onChangeObservable.notifyObservers();
|
|
19891
|
-
},
|
|
19892
|
-
});
|
|
20276
|
+
const nameHookToken = watcherService.watchProperty(material, "name", () => onChangeObservable.notifyObservers());
|
|
19893
20277
|
return {
|
|
19894
20278
|
get name() {
|
|
19895
20279
|
return material.name;
|
|
@@ -19929,8 +20313,8 @@ const MaterialExplorerServiceDefinition = {
|
|
|
19929
20313
|
|
|
19930
20314
|
const NodeExplorerServiceDefinition = {
|
|
19931
20315
|
friendlyName: "Node Explorer",
|
|
19932
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, GizmoServiceIdentity],
|
|
19933
|
-
factory: (sceneExplorerService, sceneContext, gizmoService) => {
|
|
20316
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, GizmoServiceIdentity, WatcherServiceIdentity],
|
|
20317
|
+
factory: (sceneExplorerService, sceneContext, gizmoService, watcherService) => {
|
|
19934
20318
|
const scene = sceneContext.currentScene;
|
|
19935
20319
|
if (!scene) {
|
|
19936
20320
|
return undefined;
|
|
@@ -19969,14 +20353,8 @@ const NodeExplorerServiceDefinition = {
|
|
|
19969
20353
|
getEntityChildren: (node) => node.getChildren(),
|
|
19970
20354
|
getEntityDisplayInfo: (node) => {
|
|
19971
20355
|
const onChangeObservable = new Observable();
|
|
19972
|
-
const nameHookToken =
|
|
19973
|
-
|
|
19974
|
-
});
|
|
19975
|
-
const parentHookToken = InterceptProperty(node, "parent", {
|
|
19976
|
-
afterSet: () => {
|
|
19977
|
-
nodeMovedObservable.notifyObservers(node);
|
|
19978
|
-
},
|
|
19979
|
-
});
|
|
20356
|
+
const nameHookToken = watcherService.watchProperty(node, "name", () => onChangeObservable.notifyObservers());
|
|
20357
|
+
const parentHookToken = watcherService.watchProperty(node, "parent", () => nodeMovedObservable.notifyObservers(node));
|
|
19980
20358
|
return {
|
|
19981
20359
|
get name() {
|
|
19982
20360
|
return node.name;
|
|
@@ -20039,9 +20417,7 @@ const NodeExplorerServiceDefinition = {
|
|
|
20039
20417
|
order: 1000 /* DefaultCommandsOrder.MeshBoundingBox */,
|
|
20040
20418
|
getCommand: (mesh) => {
|
|
20041
20419
|
const onChangeObservable = new Observable();
|
|
20042
|
-
const showBoundingBoxHook =
|
|
20043
|
-
afterSet: () => onChangeObservable.notifyObservers(),
|
|
20044
|
-
});
|
|
20420
|
+
const showBoundingBoxHook = watcherService.watchProperty(mesh, "showBoundingBox", () => onChangeObservable.notifyObservers());
|
|
20045
20421
|
return {
|
|
20046
20422
|
type: "toggle",
|
|
20047
20423
|
get displayName() {
|
|
@@ -20067,9 +20443,7 @@ const NodeExplorerServiceDefinition = {
|
|
|
20067
20443
|
order: 1100 /* DefaultCommandsOrder.MeshVisibility */,
|
|
20068
20444
|
getCommand: (mesh) => {
|
|
20069
20445
|
const onChangeObservable = new Observable();
|
|
20070
|
-
const isVisibleHook =
|
|
20071
|
-
afterSet: () => onChangeObservable.notifyObservers(),
|
|
20072
|
-
});
|
|
20446
|
+
const isVisibleHook = watcherService.watchProperty(mesh, "isVisible", () => onChangeObservable.notifyObservers());
|
|
20073
20447
|
return {
|
|
20074
20448
|
type: "toggle",
|
|
20075
20449
|
get displayName() {
|
|
@@ -20094,6 +20468,7 @@ const NodeExplorerServiceDefinition = {
|
|
|
20094
20468
|
};
|
|
20095
20469
|
},
|
|
20096
20470
|
});
|
|
20471
|
+
const getActiveCamera = () => (scene.frameGraph ? FindMainCamera(scene.frameGraph) : scene.activeCamera);
|
|
20097
20472
|
const activeCameraCommandRegistration = sceneExplorerService.addEntityCommand({
|
|
20098
20473
|
predicate: (entity) => entity instanceof Camera,
|
|
20099
20474
|
order: 700 /* DefaultCommandsOrder.CameraActive */,
|
|
@@ -20106,15 +20481,28 @@ const NodeExplorerServiceDefinition = {
|
|
|
20106
20481
|
return {
|
|
20107
20482
|
type: "toggle",
|
|
20108
20483
|
displayName: "Activate and Attach Controls",
|
|
20109
|
-
icon: () =>
|
|
20484
|
+
icon: () => {
|
|
20485
|
+
return getActiveCamera() === camera ? jsx(VideoFilled, {}) : jsx(VideoRegular, {});
|
|
20486
|
+
},
|
|
20110
20487
|
get isEnabled() {
|
|
20111
|
-
return
|
|
20488
|
+
return getActiveCamera() === camera;
|
|
20112
20489
|
},
|
|
20113
20490
|
set isEnabled(enabled) {
|
|
20114
|
-
|
|
20115
|
-
|
|
20116
|
-
|
|
20117
|
-
|
|
20491
|
+
const activeCamera = getActiveCamera();
|
|
20492
|
+
if (enabled && activeCamera !== camera) {
|
|
20493
|
+
activeCamera?.detachControl();
|
|
20494
|
+
if (scene.frameGraph) {
|
|
20495
|
+
const objectRenderer = FindMainObjectRenderer(scene.frameGraph);
|
|
20496
|
+
if (objectRenderer) {
|
|
20497
|
+
objectRenderer.camera = camera;
|
|
20498
|
+
onChangeObservable.notifyObservers(); // manual trigger, because scene.onActiveCameraChanged won't be triggered by the line above
|
|
20499
|
+
camera.attachControl(true);
|
|
20500
|
+
}
|
|
20501
|
+
}
|
|
20502
|
+
else {
|
|
20503
|
+
scene.activeCamera = camera;
|
|
20504
|
+
camera.attachControl(true);
|
|
20505
|
+
}
|
|
20118
20506
|
}
|
|
20119
20507
|
},
|
|
20120
20508
|
onChange: onChangeObservable,
|
|
@@ -20221,8 +20609,8 @@ const NodeExplorerServiceDefinition = {
|
|
|
20221
20609
|
|
|
20222
20610
|
const ParticleSystemExplorerServiceDefinition = {
|
|
20223
20611
|
friendlyName: "Particle System Explorer",
|
|
20224
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
20225
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20612
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20613
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
20226
20614
|
const scene = sceneContext.currentScene;
|
|
20227
20615
|
if (!scene) {
|
|
20228
20616
|
return undefined;
|
|
@@ -20233,11 +20621,7 @@ const ParticleSystemExplorerServiceDefinition = {
|
|
|
20233
20621
|
getRootEntities: () => scene.particleSystems,
|
|
20234
20622
|
getEntityDisplayInfo: (particleSystem) => {
|
|
20235
20623
|
const onChangeObservable = new Observable();
|
|
20236
|
-
const nameHookToken =
|
|
20237
|
-
afterSet: () => {
|
|
20238
|
-
onChangeObservable.notifyObservers();
|
|
20239
|
-
},
|
|
20240
|
-
});
|
|
20624
|
+
const nameHookToken = watcherService.watchProperty(particleSystem, "name", () => onChangeObservable.notifyObservers());
|
|
20241
20625
|
return {
|
|
20242
20626
|
get name() {
|
|
20243
20627
|
return particleSystem.name;
|
|
@@ -20277,8 +20661,8 @@ const ParticleSystemExplorerServiceDefinition = {
|
|
|
20277
20661
|
|
|
20278
20662
|
const PostProcessExplorerServiceDefinition = {
|
|
20279
20663
|
friendlyName: "Post Process Explorer",
|
|
20280
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
20281
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20664
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20665
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
20282
20666
|
const scene = sceneContext.currentScene;
|
|
20283
20667
|
if (!scene) {
|
|
20284
20668
|
return undefined;
|
|
@@ -20289,11 +20673,7 @@ const PostProcessExplorerServiceDefinition = {
|
|
|
20289
20673
|
getRootEntities: () => scene.postProcesses,
|
|
20290
20674
|
getEntityDisplayInfo: (postProcess) => {
|
|
20291
20675
|
const onChangeObservable = new Observable();
|
|
20292
|
-
const nameHookToken =
|
|
20293
|
-
afterSet: () => {
|
|
20294
|
-
onChangeObservable.notifyObservers();
|
|
20295
|
-
},
|
|
20296
|
-
});
|
|
20676
|
+
const nameHookToken = watcherService.watchProperty(postProcess, "name", () => onChangeObservable.notifyObservers());
|
|
20297
20677
|
return {
|
|
20298
20678
|
get name() {
|
|
20299
20679
|
return postProcess.name;
|
|
@@ -20351,8 +20731,8 @@ const RenderingPipelineExplorerServiceDefinition = {
|
|
|
20351
20731
|
|
|
20352
20732
|
const SkeletonExplorerServiceDefinition = {
|
|
20353
20733
|
friendlyName: "Skeleton Explorer",
|
|
20354
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
20355
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20734
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20735
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
20356
20736
|
const scene = sceneContext.currentScene;
|
|
20357
20737
|
if (!scene) {
|
|
20358
20738
|
return undefined;
|
|
@@ -20365,16 +20745,8 @@ const SkeletonExplorerServiceDefinition = {
|
|
|
20365
20745
|
getEntityChildren: (skeletonOrBone) => skeletonOrBone.getChildren(),
|
|
20366
20746
|
getEntityDisplayInfo: (skeletonOrBone) => {
|
|
20367
20747
|
const onChangeObservable = new Observable();
|
|
20368
|
-
const nameHookToken =
|
|
20369
|
-
|
|
20370
|
-
});
|
|
20371
|
-
const parentHookToken = skeletonOrBone instanceof Skeleton
|
|
20372
|
-
? null
|
|
20373
|
-
: InterceptProperty(skeletonOrBone, "parent", {
|
|
20374
|
-
afterSet: () => {
|
|
20375
|
-
boneMovedObservable.notifyObservers(skeletonOrBone);
|
|
20376
|
-
},
|
|
20377
|
-
});
|
|
20748
|
+
const nameHookToken = watcherService.watchProperty(skeletonOrBone, "name", () => onChangeObservable.notifyObservers());
|
|
20749
|
+
const parentHookToken = skeletonOrBone instanceof Skeleton ? null : watcherService.watchProperty(skeletonOrBone, "parent", () => boneMovedObservable.notifyObservers(skeletonOrBone));
|
|
20378
20750
|
return {
|
|
20379
20751
|
get name() {
|
|
20380
20752
|
return skeletonOrBone.name;
|
|
@@ -20402,8 +20774,8 @@ const SkeletonExplorerServiceDefinition = {
|
|
|
20402
20774
|
|
|
20403
20775
|
const SoundExplorerServiceDefinition = {
|
|
20404
20776
|
friendlyName: "Sound Explorer",
|
|
20405
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
20406
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20777
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20778
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
20407
20779
|
const scene = sceneContext.currentScene;
|
|
20408
20780
|
if (!scene) {
|
|
20409
20781
|
return undefined;
|
|
@@ -20429,25 +20801,14 @@ const SoundExplorerServiceDefinition = {
|
|
|
20429
20801
|
// If _mainSoundTrack is already defined, set up hooks immediately.
|
|
20430
20802
|
hookMainSoundTrack(scene.mainSoundTrack);
|
|
20431
20803
|
// Watch for _mainSoundTrack being set (it is lazily created by the mainSoundTrack getter in audioSceneComponent.ts).
|
|
20432
|
-
const mainSoundTrackHook =
|
|
20433
|
-
afterSet: () => hookMainSoundTrack(scene._mainSoundTrack),
|
|
20434
|
-
});
|
|
20804
|
+
const mainSoundTrackHook = watcherService.watchProperty(scene, "_mainSoundTrack", () => hookMainSoundTrack(scene._mainSoundTrack));
|
|
20435
20805
|
const sectionRegistration = sceneExplorerService.addSection({
|
|
20436
20806
|
displayName: "Sounds",
|
|
20437
20807
|
order: 1400 /* DefaultSectionsOrder.Sounds */,
|
|
20438
20808
|
getRootEntities: () => scene.mainSoundTrack?.soundCollection ?? [],
|
|
20439
20809
|
getEntityDisplayInfo: (sound) => {
|
|
20440
20810
|
const onChangeObservable = new Observable();
|
|
20441
|
-
const
|
|
20442
|
-
afterSet: () => {
|
|
20443
|
-
onChangeObservable.notifyObservers();
|
|
20444
|
-
},
|
|
20445
|
-
});
|
|
20446
|
-
const nameHookToken = InterceptProperty(sound, "name", {
|
|
20447
|
-
afterSet: () => {
|
|
20448
|
-
onChangeObservable.notifyObservers();
|
|
20449
|
-
},
|
|
20450
|
-
});
|
|
20811
|
+
const nameHookToken = watcherService.watchProperty(sound, "name", () => onChangeObservable.notifyObservers());
|
|
20451
20812
|
return {
|
|
20452
20813
|
get name() {
|
|
20453
20814
|
return sound.name;
|
|
@@ -20455,7 +20816,6 @@ const SoundExplorerServiceDefinition = {
|
|
|
20455
20816
|
onChange: onChangeObservable,
|
|
20456
20817
|
dispose: () => {
|
|
20457
20818
|
nameHookToken.dispose();
|
|
20458
|
-
displayNameHookToken.dispose();
|
|
20459
20819
|
onChangeObservable.clear();
|
|
20460
20820
|
},
|
|
20461
20821
|
};
|
|
@@ -20479,8 +20839,8 @@ const SoundExplorerServiceDefinition = {
|
|
|
20479
20839
|
|
|
20480
20840
|
const SpriteManagerExplorerServiceDefinition = {
|
|
20481
20841
|
friendlyName: "Sprite Manager Explorer",
|
|
20482
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
20483
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20842
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20843
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
20484
20844
|
const scene = sceneContext.currentScene;
|
|
20485
20845
|
if (!scene) {
|
|
20486
20846
|
return undefined;
|
|
@@ -20492,9 +20852,7 @@ const SpriteManagerExplorerServiceDefinition = {
|
|
|
20492
20852
|
getEntityChildren: (spriteEntity) => (spriteEntity instanceof Sprite ? [] : spriteEntity.sprites),
|
|
20493
20853
|
getEntityDisplayInfo: (spriteEntity) => {
|
|
20494
20854
|
const onChangeObservable = new Observable();
|
|
20495
|
-
const nameHookToken =
|
|
20496
|
-
afterSet: () => onChangeObservable.notifyObservers(),
|
|
20497
|
-
});
|
|
20855
|
+
const nameHookToken = watcherService.watchProperty(spriteEntity, "name", () => onChangeObservable.notifyObservers());
|
|
20498
20856
|
return {
|
|
20499
20857
|
get name() {
|
|
20500
20858
|
return spriteEntity.name;
|
|
@@ -20552,8 +20910,8 @@ const SpriteManagerExplorerServiceDefinition = {
|
|
|
20552
20910
|
|
|
20553
20911
|
const TextureExplorerServiceDefinition = {
|
|
20554
20912
|
friendlyName: "Texture Explorer",
|
|
20555
|
-
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
20556
|
-
factory: (sceneExplorerService, sceneContext) => {
|
|
20913
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, WatcherServiceIdentity],
|
|
20914
|
+
factory: (sceneExplorerService, sceneContext, watcherService) => {
|
|
20557
20915
|
const scene = sceneContext.currentScene;
|
|
20558
20916
|
if (!scene) {
|
|
20559
20917
|
return undefined;
|
|
@@ -20564,16 +20922,8 @@ const TextureExplorerServiceDefinition = {
|
|
|
20564
20922
|
getRootEntities: () => scene.textures.filter((texture) => texture.getClassName() !== "AdvancedDynamicTexture"),
|
|
20565
20923
|
getEntityDisplayInfo: (texture) => {
|
|
20566
20924
|
const onChangeObservable = new Observable();
|
|
20567
|
-
const displayNameHookToken =
|
|
20568
|
-
|
|
20569
|
-
onChangeObservable.notifyObservers();
|
|
20570
|
-
},
|
|
20571
|
-
});
|
|
20572
|
-
const nameHookToken = InterceptProperty(texture, "name", {
|
|
20573
|
-
afterSet: () => {
|
|
20574
|
-
onChangeObservable.notifyObservers();
|
|
20575
|
-
},
|
|
20576
|
-
});
|
|
20925
|
+
const displayNameHookToken = watcherService.watchProperty(texture, "displayName", () => onChangeObservable.notifyObservers());
|
|
20926
|
+
const nameHookToken = watcherService.watchProperty(texture, "name", () => onChangeObservable.notifyObservers());
|
|
20577
20927
|
return {
|
|
20578
20928
|
get name() {
|
|
20579
20929
|
return texture.displayName || texture.name || `${texture.getClassName() || "Unnamed Texture"} (${texture.uniqueId})`;
|
|
@@ -21123,97 +21473,6 @@ const GLTFValidationServiceDefinition = {
|
|
|
21123
21473
|
},
|
|
21124
21474
|
};
|
|
21125
21475
|
|
|
21126
|
-
const HighlightSelectedEntitySettingDescriptor = {
|
|
21127
|
-
key: "HighlightSelectedEntity",
|
|
21128
|
-
defaultValue: true,
|
|
21129
|
-
};
|
|
21130
|
-
const HighlightServiceDefinition = {
|
|
21131
|
-
friendlyName: "Highlight Service",
|
|
21132
|
-
consumes: [SelectionServiceIdentity, SceneContextIdentity, SettingsStoreIdentity, ThemeServiceIdentity, GizmoServiceIdentity],
|
|
21133
|
-
factory: (selectionService, sceneContext, settingsStore, themeService, gizmoService) => {
|
|
21134
|
-
let outlineLayer = null;
|
|
21135
|
-
let utilityLayer = null;
|
|
21136
|
-
let currentScene = null;
|
|
21137
|
-
let activeCameraObserver = null;
|
|
21138
|
-
function disposeOutlineLayer() {
|
|
21139
|
-
outlineLayer?.dispose();
|
|
21140
|
-
outlineLayer = null;
|
|
21141
|
-
utilityLayer?.dispose();
|
|
21142
|
-
utilityLayer = null;
|
|
21143
|
-
currentScene = null;
|
|
21144
|
-
}
|
|
21145
|
-
function getOrCreateOutlineLayer(scene) {
|
|
21146
|
-
if (!outlineLayer || currentScene !== scene) {
|
|
21147
|
-
disposeOutlineLayer();
|
|
21148
|
-
utilityLayer = gizmoService.getUtilityLayer(scene);
|
|
21149
|
-
outlineLayer = new SelectionOutlineLayer("InspectorSelectionOutline", utilityLayer.value.utilityLayerScene);
|
|
21150
|
-
updateColor(outlineLayer);
|
|
21151
|
-
currentScene = scene;
|
|
21152
|
-
}
|
|
21153
|
-
return outlineLayer;
|
|
21154
|
-
}
|
|
21155
|
-
function updateColor(outlineLayer) {
|
|
21156
|
-
outlineLayer.outlineColor = Color3.FromHexString(themeService.theme.colorBrandForeground1);
|
|
21157
|
-
}
|
|
21158
|
-
function updateHighlight() {
|
|
21159
|
-
const scene = sceneContext.currentScene;
|
|
21160
|
-
const entity = selectionService.selectedEntity instanceof AbstractMesh && !(selectionService.selectedEntity instanceof GaussianSplattingMesh)
|
|
21161
|
-
? selectionService.selectedEntity
|
|
21162
|
-
: null;
|
|
21163
|
-
if (!entity || !settingsStore.readSetting(HighlightSelectedEntitySettingDescriptor) || !scene || !scene.activeCamera) {
|
|
21164
|
-
disposeOutlineLayer();
|
|
21165
|
-
return;
|
|
21166
|
-
}
|
|
21167
|
-
const layer = getOrCreateOutlineLayer(scene);
|
|
21168
|
-
layer.clearSelection();
|
|
21169
|
-
layer.addSelection(entity);
|
|
21170
|
-
}
|
|
21171
|
-
function watchActiveCamera(scene) {
|
|
21172
|
-
activeCameraObserver?.remove();
|
|
21173
|
-
activeCameraObserver = null;
|
|
21174
|
-
if (scene) {
|
|
21175
|
-
activeCameraObserver = scene.onActiveCameraChanged.add(updateHighlight);
|
|
21176
|
-
}
|
|
21177
|
-
}
|
|
21178
|
-
// React to theme changes.
|
|
21179
|
-
const themeObserver = themeService.onChanged.add(() => {
|
|
21180
|
-
if (outlineLayer) {
|
|
21181
|
-
updateColor(outlineLayer);
|
|
21182
|
-
}
|
|
21183
|
-
});
|
|
21184
|
-
// React to selection changes.
|
|
21185
|
-
const selectionObserver = selectionService.onSelectedEntityChanged.add(updateHighlight);
|
|
21186
|
-
// React to scene changes.
|
|
21187
|
-
const sceneObserver = sceneContext.currentSceneObservable.add(() => {
|
|
21188
|
-
// Dispose the old layer when the scene changes.
|
|
21189
|
-
disposeOutlineLayer();
|
|
21190
|
-
watchActiveCamera(sceneContext.currentScene);
|
|
21191
|
-
updateHighlight();
|
|
21192
|
-
});
|
|
21193
|
-
// React to setting changes.
|
|
21194
|
-
const settingObserver = settingsStore.onChanged.add((setting) => {
|
|
21195
|
-
if (setting === HighlightSelectedEntitySettingDescriptor.key) {
|
|
21196
|
-
updateHighlight();
|
|
21197
|
-
}
|
|
21198
|
-
});
|
|
21199
|
-
// Watch active camera on the initial scene.
|
|
21200
|
-
watchActiveCamera(sceneContext.currentScene);
|
|
21201
|
-
// Initial update.
|
|
21202
|
-
updateHighlight();
|
|
21203
|
-
return {
|
|
21204
|
-
dispose: () => {
|
|
21205
|
-
themeObserver.remove();
|
|
21206
|
-
selectionObserver.remove();
|
|
21207
|
-
sceneObserver.remove();
|
|
21208
|
-
settingObserver.remove();
|
|
21209
|
-
activeCameraObserver?.remove();
|
|
21210
|
-
activeCameraObserver = null;
|
|
21211
|
-
disposeOutlineLayer();
|
|
21212
|
-
},
|
|
21213
|
-
};
|
|
21214
|
-
},
|
|
21215
|
-
};
|
|
21216
|
-
|
|
21217
21476
|
const PickingToolbar = (props) => {
|
|
21218
21477
|
const { scene, selectEntity, gizmoService, ignoreBackfaces, highlightSelectedEntity, onHighlightSelectedEntityChange } = props;
|
|
21219
21478
|
const meshDataCache = useMemo(() => new WeakMap(), [scene]);
|
|
@@ -21322,7 +21581,7 @@ const PickingServiceDefinition = {
|
|
|
21322
21581
|
key: "Picking Service",
|
|
21323
21582
|
verticalLocation: "top",
|
|
21324
21583
|
horizontalLocation: "left",
|
|
21325
|
-
|
|
21584
|
+
teachingMoment: false,
|
|
21326
21585
|
component: () => {
|
|
21327
21586
|
const scene = useObservableState(() => sceneContext.currentScene, sceneContext.currentSceneObservable);
|
|
21328
21587
|
const selectEntity = useCallback((entity) => (selectionService.selectedEntity = entity), []);
|
|
@@ -21378,7 +21637,11 @@ const UserFeedbackServiceDefinition = {
|
|
|
21378
21637
|
key: "User Feedback",
|
|
21379
21638
|
verticalLocation: "bottom",
|
|
21380
21639
|
horizontalLocation: "right",
|
|
21381
|
-
|
|
21640
|
+
order: 100 /* DefaultToolbarItemOrder.Feedback */,
|
|
21641
|
+
teachingMoment: {
|
|
21642
|
+
title: "Feedback",
|
|
21643
|
+
description: "Press this button to give feedback on Inspector v2 and help us prioritize new features and improvements!",
|
|
21644
|
+
},
|
|
21382
21645
|
component: () => {
|
|
21383
21646
|
return (jsx(Tooltip, { content: "Give Feedback on Inspector v2", children: jsx(Button, { appearance: "subtle", icon: PersonFeedbackRegular, onClick: () => window.open("https://forum.babylonjs.com/t/introducing-inspector-v2/60937", "_blank") }) }));
|
|
21384
21647
|
},
|
|
@@ -21569,7 +21832,9 @@ function ShowInspector(scene, options = {}) {
|
|
|
21569
21832
|
// Tools pane tab and related services.
|
|
21570
21833
|
ToolsServiceDefinition, ExportServiceDefinition, GLTFAnimationImportServiceDefinition, GLTFLoaderOptionsServiceDefinition, GLTFValidationServiceDefinition, CaptureToolsDefinition,
|
|
21571
21834
|
// Settings pane tab and related services.
|
|
21572
|
-
SettingsServiceDefinition, ShellSettingsServiceDefinition,
|
|
21835
|
+
SettingsServiceDefinition, WatcherSettingsServiceDefinition, ShellSettingsServiceDefinition,
|
|
21836
|
+
// Adds a button to refresh all properties manually (when watcher is in "manual" mode).
|
|
21837
|
+
WatcherRefreshToolbarServiceDefinition,
|
|
21573
21838
|
// Tracks entity selection state (e.g. which Mesh or Material or other entity is currently selected in scene explorer and bound to the properties pane, etc.).
|
|
21574
21839
|
SelectionServiceDefinition,
|
|
21575
21840
|
// Gizmos for manipulating objects in the scene.
|
|
@@ -21803,19 +22068,15 @@ function ConvertOptions(v1Options) {
|
|
|
21803
22068
|
const { additionalNodes } = v1Options;
|
|
21804
22069
|
const additionalNodesServiceDefinition = {
|
|
21805
22070
|
friendlyName: "Additional Nodes (Backward Compatibility)",
|
|
21806
|
-
consumes: [SceneExplorerServiceIdentity],
|
|
21807
|
-
factory: (sceneExplorerService) => {
|
|
22071
|
+
consumes: [SceneExplorerServiceIdentity, WatcherServiceIdentity],
|
|
22072
|
+
factory: (sceneExplorerService, watcherService) => {
|
|
21808
22073
|
const sceneExplorerSectionRegistrations = additionalNodes.map((node) => sceneExplorerService.addSection({
|
|
21809
22074
|
displayName: node.name,
|
|
21810
22075
|
order: Number.MAX_SAFE_INTEGER,
|
|
21811
22076
|
getRootEntities: () => node.getContent(),
|
|
21812
22077
|
getEntityDisplayInfo: (entity) => {
|
|
21813
22078
|
const onChangeObservable = new Observable();
|
|
21814
|
-
const nameHookToken =
|
|
21815
|
-
afterSet: () => {
|
|
21816
|
-
onChangeObservable.notifyObservers();
|
|
21817
|
-
},
|
|
21818
|
-
});
|
|
22079
|
+
const nameHookToken = watcherService.watchProperty(entity, "name", () => onChangeObservable.notifyObservers());
|
|
21819
22080
|
return {
|
|
21820
22081
|
get name() {
|
|
21821
22082
|
return entity.name;
|
|
@@ -21949,7 +22210,7 @@ class Inspector {
|
|
|
21949
22210
|
this.MarkMultipleLineContainerTitlesForHighlighting([title]);
|
|
21950
22211
|
}
|
|
21951
22212
|
static MarkMultipleLineContainerTitlesForHighlighting(titles) {
|
|
21952
|
-
this.
|
|
22213
|
+
this._OnMarkLineContainerObservable.notifyObservers(titles);
|
|
21953
22214
|
}
|
|
21954
22215
|
static PopupEmbed() {
|
|
21955
22216
|
this._PopupToggler?.("right");
|
|
@@ -21973,6 +22234,13 @@ class Inspector {
|
|
|
21973
22234
|
if (!scene || scene.isDisposed) {
|
|
21974
22235
|
return;
|
|
21975
22236
|
}
|
|
22237
|
+
// Inspector setup is async, so we need to cache pending selection requests.
|
|
22238
|
+
// Additionally, we manually track this (rather than relying on the observable's notifyIfTriggered property)
|
|
22239
|
+
// for behavior backward compatibility.
|
|
22240
|
+
let pendingSelection = null;
|
|
22241
|
+
const pendingSelectionObserver = this.OnSelectionChangeObservable.add((entity) => {
|
|
22242
|
+
pendingSelection = entity;
|
|
22243
|
+
});
|
|
21976
22244
|
let options = ConvertOptions(userOptions);
|
|
21977
22245
|
const serviceDefinitions = [];
|
|
21978
22246
|
const popupServiceDefinition = {
|
|
@@ -22006,6 +22274,13 @@ class Inspector {
|
|
|
22006
22274
|
const legacyObserver = this.OnSelectionChangeObservable.add((entity) => {
|
|
22007
22275
|
selectionService.selectedEntity = entity;
|
|
22008
22276
|
});
|
|
22277
|
+
// If a selection was requested before async setup completed, apply it now.
|
|
22278
|
+
if (pendingSelection) {
|
|
22279
|
+
selectionService.selectedEntity = pendingSelection;
|
|
22280
|
+
pendingSelection = null;
|
|
22281
|
+
}
|
|
22282
|
+
// Now the service is alive so we don't need to track pending selection requests.
|
|
22283
|
+
pendingSelectionObserver.remove();
|
|
22009
22284
|
return {
|
|
22010
22285
|
dispose: () => {
|
|
22011
22286
|
selectionServiceObserver.remove();
|
|
@@ -22039,12 +22314,17 @@ class Inspector {
|
|
|
22039
22314
|
friendlyName: "Section Highlighter Service (Backward Compatibility)",
|
|
22040
22315
|
consumes: [PropertiesServiceIdentity],
|
|
22041
22316
|
factory: (propertiesService) => {
|
|
22042
|
-
|
|
22043
|
-
propertiesService.highlightSections(
|
|
22044
|
-
};
|
|
22317
|
+
const markLineContainerObserver = this._OnMarkLineContainerObservable.add((sections) => {
|
|
22318
|
+
propertiesService.highlightSections(sections.map((id) => LegacyPropertiesSectionMapping[id] ?? id));
|
|
22319
|
+
});
|
|
22320
|
+
// Now the service is alive so we don't need to track pending highlight requests.
|
|
22321
|
+
this._OnMarkLineContainerObservable.notifyIfTriggered = false;
|
|
22322
|
+
this._OnMarkLineContainerObservable.cleanLastNotifiedState();
|
|
22045
22323
|
return {
|
|
22046
22324
|
dispose: () => {
|
|
22047
|
-
|
|
22325
|
+
// Service is being torn down, so start caching pending highlight requests again.
|
|
22326
|
+
markLineContainerObserver.remove();
|
|
22327
|
+
this._OnMarkLineContainerObservable.notifyIfTriggered = true;
|
|
22048
22328
|
},
|
|
22049
22329
|
};
|
|
22050
22330
|
},
|
|
@@ -22094,10 +22374,10 @@ class Inspector {
|
|
|
22094
22374
|
}
|
|
22095
22375
|
Inspector._CurrentInstance = null;
|
|
22096
22376
|
Inspector._PopupToggler = null;
|
|
22097
|
-
Inspector._SectionHighlighter = null;
|
|
22098
22377
|
Inspector._SidePaneOpenCounter = null;
|
|
22099
22378
|
Inspector.OnSelectionChangeObservable = new Observable();
|
|
22100
22379
|
Inspector.OnPropertyChangedObservable = new Observable();
|
|
22380
|
+
Inspector._OnMarkLineContainerObservable = new Observable(undefined, true);
|
|
22101
22381
|
|
|
22102
22382
|
var inspector = /*#__PURE__*/Object.freeze({
|
|
22103
22383
|
__proto__: null,
|
|
@@ -22406,5 +22686,5 @@ const TextAreaPropertyLine = (props) => {
|
|
|
22406
22686
|
// Attach Inspector v2 to Scene.debugLayer as a side effect for back compat.
|
|
22407
22687
|
AttachDebugLayer();
|
|
22408
22688
|
|
|
22409
|
-
export { useEventfulState as $, Accordion as A, Button as B, CheckboxPropertyLine as C, DebugServiceIdentity as D,
|
|
22410
|
-
//# sourceMappingURL=index-
|
|
22689
|
+
export { useEventfulState as $, Accordion as A, Button as B, CheckboxPropertyLine as C, DebugServiceIdentity as D, ErrorBoundary as E, ExtensibleAccordion as F, GizmoServiceIdentity as G, Theme as H, Inspector as I, TeachingMoment as J, PropertyContext as K, LinkToEntity as L, MessageBar as M, NumberInputPropertyLine as N, usePropertyChangedNotifier as O, Popover as P, BuiltInsExtensionFeed as Q, useVector3Property as R, SpinButtonPropertyLine as S, TextInputPropertyLine as T, useColor3Property as U, Vector3PropertyLine as V, WatcherServiceIdentity as W, useColor4Property as X, useQuaternionProperty as Y, MakePropertyHook as Z, useInterceptObservable as _, useProperty as a, Color3GradientList as a$, useObservableCollection as a0, useOrderedObservableCollection as a1, usePollingObservable as a2, useResource as a3, useAsyncResource as a4, useSetting as a5, useAngleConverters as a6, MakeTeachingMoment as a7, MakeDialogTeachingMoment as a8, MakePopoverTeachingMoment as a9, FactorGradientComponent as aA, Color3GradientComponent as aB, Color4GradientComponent as aC, ColorStepGradientComponent as aD, InfoLabel as aE, MakeLazyComponent as aF, List as aG, MaterialSelector as aH, NodeSelector as aI, PositionedPopover as aJ, SearchBar as aK, SearchBox as aL, SkeletonSelector as aM, Slider as aN, SpinButton as aO, Switch as aP, SyncedSliderInput as aQ, Textarea as aR, TextInput as aS, TextureSelector as aT, ToastProvider as aU, ToggleButton as aV, Tooltip as aW, UploadButton as aX, ChildWindow as aY, FileUploadLine as aZ, FactorGradientList as a_, useThemeMode as aa, useTheme as ab, InterceptFunction as ac, GetPropertyDescriptor as ad, IsPropertyReadonly as ae, InterceptProperty as af, ObservableCollection as ag, ConstructorFactory as ah, SelectionServiceDefinition as ai, SettingsStore as aj, ShowInspector as ak, useKeyListener as al, useKeyState as am, useEventListener as an, AccordionSectionItem as ao, Checkbox as ap, Collapse as aq, ColorPickerPopup as ar, InputHexField as as, InputHsvField as at, ComboBox as au, DraggableLine as av, Dropdown as aw, NumberDropdown as ax, StringDropdown as ay, EntitySelector as az, ShellServiceIdentity as b, Color4GradientList as b0, Pane as b1, TextureUpload as b2, BooleanBadgePropertyLine as b3, Color3PropertyLine as b4, Color4PropertyLine as b5, ComboBoxPropertyLine as b6, HexPropertyLine as b7, LinkPropertyLine as b8, PropertyLine as b9, LineContainer as ba, PlaceholderPropertyLine as bb, StringifiedPropertyLine as bc, SwitchPropertyLine as bd, SyncedSliderPropertyLine as be, TextAreaPropertyLine as bf, TextPropertyLine as bg, RotationVectorPropertyLine as bh, QuaternionPropertyLine as bi, Vector2PropertyLine as bj, Vector4PropertyLine as bk, SceneContextIdentity as c, SelectionServiceIdentity as d, useObservableState as e, AccordionSection as f, ButtonLine as g, ToolsServiceIdentity as h, useExtensionManager as i, Link as j, SidePaneContainer as k, PropertiesServiceIdentity as l, SceneExplorerServiceIdentity as m, SettingsServiceIdentity as n, StatsServiceIdentity as o, ThemeServiceIdentity as p, SettingsStoreIdentity as q, ConvertOptions as r, AttachDebugLayer as s, DetachDebugLayer as t, useToast as u, NumberDropdownPropertyLine as v, StringDropdownPropertyLine as w, BoundProperty as x, Property as y, LinkToEntityPropertyLine as z };
|
|
22690
|
+
//# sourceMappingURL=index-Ddfh2kw4.js.map
|