@babylonjs/inspector 9.9.1 → 9.9.2
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/components/properties/audio/audioV2Properties.d.ts +93 -0
- package/lib/components/properties/audio/audioV2SpatialProperties.d.ts +12 -0
- package/lib/components/properties/materials/materialTextureDebugPropertyLine.d.ts +18 -0
- package/lib/{extensionsListService-Drj94Pma.js → extensionsListService-j6viqje8.js} +11 -2
- package/lib/{extensionsListService-Drj94Pma.js.map → extensionsListService-j6viqje8.js.map} +1 -1
- package/lib/{index-UoPnMkyH.js → index--oJsOVVX.js} +1178 -271
- package/lib/index--oJsOVVX.js.map +1 -0
- package/lib/index.js +10 -1
- package/lib/index.js.map +1 -1
- package/lib/{quickCreateToolsService-CXUBvaDf.js → quickCreateToolsService-eZ4MCuJ2.js} +11 -2
- package/lib/{quickCreateToolsService-CXUBvaDf.js.map → quickCreateToolsService-eZ4MCuJ2.js.map} +1 -1
- package/lib/{reflectorService-D3JRLq4p.js → reflectorService-2dP-GJrK.js} +11 -2
- package/lib/{reflectorService-D3JRLq4p.js.map → reflectorService-2dP-GJrK.js.map} +1 -1
- package/lib/services/gizmoService.d.ts +9 -0
- package/lib/services/panes/properties/audioPropertiesService.d.ts +2 -1
- package/lib/services/panes/scene/audioV2ExplorerService.d.ts +6 -0
- package/lib/services/panes/scene/defaultSectionsMetadata.d.ts +2 -1
- package/package.json +1 -1
- package/lib/index-UoPnMkyH.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, useImperativeHandle, cloneElement, 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, Body1Strong, mergeClasses, useId, useToastController, Toast, ToastTitle, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody,
|
|
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, WarningRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, ArrowUploadRegular, ArrowBidirectionalUpDownFilled, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, ArrowClockwiseRegular, WeatherSunnyRegular, WeatherMoonRegular, PlugDisconnectedRegular, PlugConnectedRegular, PlugConnectedCheckmarkRegular, 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, BubbleMultipleRegular, LightbulbRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular,
|
|
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, Body1Strong, mergeClasses, useId, useToastController, Toast, ToastTitle, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, createDOMRenderer, RendererProvider, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, Switch as Switch$1, treeItemLevelToken, typographyStyles, 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 as Dialog$1, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, Badge, Label, MessageBarTitle, useComboboxFilter, Combobox, Subtitle2, Textarea as Textarea$1, ToolbarButton, ToolbarDivider, DialogTrigger, 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, WarningRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, ArrowUploadRegular, ArrowBidirectionalUpDownFilled, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, ArrowClockwiseRegular, WeatherSunnyRegular, WeatherMoonRegular, InfoRegular, CheckmarkCircleRegular, PlugDisconnectedRegular, PlugConnectedRegular, PlugConnectedCheckmarkRegular, 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, HeadphonesSoundWaveRegular, ArrowEnterUpRegular, SoundWaveCircleRegular, SoundWaveCircleFilled, CatchUpRegular, LayerRegular, FrameRegular, AppGenericRegular, RectangleLandscapeRegular, BorderOutsideRegular, BorderNoneRegular, MyLocationRegular, BubbleMultipleRegular, LightbulbRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, LinkRegular, ArrowSyncRegular, TargetRegular, PersonFeedbackRegular, DismissRegular, 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';
|
|
@@ -42,6 +42,7 @@ import { FrameGraphUtils, FindMainCamera } from '@babylonjs/core/FrameGraph/fram
|
|
|
42
42
|
import { CameraGizmo } from '@babylonjs/core/Gizmos/cameraGizmo.js';
|
|
43
43
|
import { GizmoManager } from '@babylonjs/core/Gizmos/gizmoManager.js';
|
|
44
44
|
import { LightGizmo } from '@babylonjs/core/Gizmos/lightGizmo.js';
|
|
45
|
+
import { SpatialAudioGizmo } from '@babylonjs/core/Gizmos/spatialAudioGizmo.js';
|
|
45
46
|
import { Light } from '@babylonjs/core/Lights/light.js';
|
|
46
47
|
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh.js';
|
|
47
48
|
import { Node as Node$1 } from '@babylonjs/core/node.js';
|
|
@@ -53,6 +54,13 @@ import { AnimationGroup, TargetedAnimation } from '@babylonjs/core/Animations/an
|
|
|
53
54
|
import { Animation } from '@babylonjs/core/Animations/animation.js';
|
|
54
55
|
import { AnimationPropertiesOverride } from '@babylonjs/core/Animations/animationPropertiesOverride.js';
|
|
55
56
|
import { Sound } from '@babylonjs/core/Audio/sound.js';
|
|
57
|
+
import { AbstractAudioBus } from '@babylonjs/core/AudioV2/abstractAudio/abstractAudioBus.js';
|
|
58
|
+
import { AbstractSound } from '@babylonjs/core/AudioV2/abstractAudio/abstractSound.js';
|
|
59
|
+
import { AbstractSoundSource } from '@babylonjs/core/AudioV2/abstractAudio/abstractSoundSource.js';
|
|
60
|
+
import { AudioBus } from '@babylonjs/core/AudioV2/abstractAudio/audioBus.js';
|
|
61
|
+
import { AudioEngineV2, OnAudioEngineV2CreatedObservable, LastCreatedAudioEngine } from '@babylonjs/core/AudioV2/abstractAudio/audioEngineV2.js';
|
|
62
|
+
import { StaticSound } from '@babylonjs/core/AudioV2/abstractAudio/staticSound.js';
|
|
63
|
+
import { StreamingSound } from '@babylonjs/core/AudioV2/abstractAudio/streamingSound.js';
|
|
56
64
|
import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera.js';
|
|
57
65
|
import { FollowCamera } from '@babylonjs/core/Cameras/followCamera.js';
|
|
58
66
|
import { FreeCamera } from '@babylonjs/core/Cameras/freeCamera.js';
|
|
@@ -135,6 +143,7 @@ import { EnvCubeTexture } from '@babylonjs/core/Materials/Textures/envCubeTextur
|
|
|
135
143
|
import { MultiRenderTarget } from '@babylonjs/core/Materials/Textures/multiRenderTarget.js';
|
|
136
144
|
import { RenderTargetTexture } from '@babylonjs/core/Materials/Textures/renderTargetTexture.js';
|
|
137
145
|
import { ThinTexture } from '@babylonjs/core/Materials/Textures/thinTexture.js';
|
|
146
|
+
import { MainAudioBus } from '@babylonjs/core/AudioV2/abstractAudio/mainAudioBus.js';
|
|
138
147
|
import '@babylonjs/core/Rendering/boundingBoxRenderer.js';
|
|
139
148
|
import '@babylonjs/core/PostProcesses/RenderPipeline/postProcessRenderPipelineManagerSceneComponent.js';
|
|
140
149
|
import '@babylonjs/core/Sprites/spriteSceneComponent.js';
|
|
@@ -248,11 +257,11 @@ function ValidateColorHex(val) {
|
|
|
248
257
|
// forwardRef wrapper to avoid "function components cannot be given refs" warning
|
|
249
258
|
// FluentTooltip handles ref forwarding to children internally via applyTriggerPropsToChildren
|
|
250
259
|
const Tooltip = forwardRef((props, _ref) => {
|
|
251
|
-
const { content, children } = props;
|
|
260
|
+
const { content, positioning, children } = props;
|
|
252
261
|
if (!content) {
|
|
253
262
|
return children;
|
|
254
263
|
}
|
|
255
|
-
return (jsx(Tooltip$1, { relationship: "description", content: content, children: children }));
|
|
264
|
+
return (jsx(Tooltip$1, { relationship: "description", content: content, positioning: positioning, children: children }));
|
|
256
265
|
});
|
|
257
266
|
Tooltip.displayName = "Tooltip";
|
|
258
267
|
|
|
@@ -268,7 +277,7 @@ const Button = forwardRef((props, ref) => {
|
|
|
268
277
|
const { size } = useContext(ToolContext);
|
|
269
278
|
const classes = useButtonStyles();
|
|
270
279
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
271
|
-
const { icon: Icon, label, onClick, disabled, className, title, ...buttonProps } = props;
|
|
280
|
+
const { icon: Icon, label, onClick, disabled, className, title, ariaLabel, ...buttonProps } = props;
|
|
272
281
|
const [isOnClickBusy, setIsOnClickBusy] = useState(false);
|
|
273
282
|
const handleOnClick = useCallback(async (e) => {
|
|
274
283
|
const result = onClick?.(e);
|
|
@@ -283,11 +292,11 @@ const Button = forwardRef((props, ref) => {
|
|
|
283
292
|
}
|
|
284
293
|
}, [onClick]);
|
|
285
294
|
const iconClass = size === "small" ? classes.smallIcon : classes.mediumIcon;
|
|
286
|
-
return (jsx(Tooltip, { content: title ?? "", children: jsx(Button$1, { ref: ref, iconPosition: "after", ...buttonProps, className: className, size: size, icon: isOnClickBusy ? jsx(Spinner, { size: "extra-tiny" }) : Icon && jsx(Icon, { className: iconClass }), onClick: handleOnClick, disabled: disabled || isOnClickBusy, children: label && props.label }) }));
|
|
295
|
+
return (jsx(Tooltip, { content: title ?? "", children: jsx(Button$1, { ref: ref, iconPosition: "after", ...buttonProps, className: className, size: size, "aria-label": ariaLabel ?? (!label ? title : undefined), icon: isOnClickBusy ? jsx(Spinner, { size: "extra-tiny" }) : Icon && jsx(Icon, { className: iconClass }), onClick: handleOnClick, disabled: disabled || isOnClickBusy, children: label && props.label }) }));
|
|
287
296
|
});
|
|
288
297
|
Button.displayName = "Button";
|
|
289
298
|
|
|
290
|
-
const useStyles$
|
|
299
|
+
const useStyles$11 = makeStyles({
|
|
291
300
|
root: {
|
|
292
301
|
display: "flex",
|
|
293
302
|
flexDirection: "column",
|
|
@@ -296,6 +305,9 @@ const useStyles$10 = makeStyles({
|
|
|
296
305
|
padding: TokenMap.px20,
|
|
297
306
|
backgroundColor: tokens.colorNeutralBackground1,
|
|
298
307
|
color: tokens.colorNeutralForeground1,
|
|
308
|
+
// Claim the full row of the flex parent (e.g. shellService's central-content row)
|
|
309
|
+
// so the centered children sit in the middle of the available area, not at the left edge.
|
|
310
|
+
flex: 1,
|
|
299
311
|
height: "100%",
|
|
300
312
|
minHeight: "100px",
|
|
301
313
|
},
|
|
@@ -368,7 +380,7 @@ class ErrorBoundary extends Component {
|
|
|
368
380
|
}
|
|
369
381
|
}
|
|
370
382
|
function ErrorFallback({ error, onRetry }) {
|
|
371
|
-
const styles = useStyles$
|
|
383
|
+
const styles = useStyles$11();
|
|
372
384
|
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 })] }));
|
|
373
385
|
}
|
|
374
386
|
|
|
@@ -466,9 +478,13 @@ function InterceptProperty(target, propertyKey, hooks) {
|
|
|
466
478
|
// Replace the property with a new one that calls the hooks in addition to the original getter and setter.
|
|
467
479
|
!Reflect.defineProperty(target, propertyKey, {
|
|
468
480
|
configurable: true,
|
|
469
|
-
get: getValue
|
|
470
|
-
|
|
471
|
-
|
|
481
|
+
get: getValue
|
|
482
|
+
? function () {
|
|
483
|
+
return getValue.call(this);
|
|
484
|
+
}
|
|
485
|
+
: undefined,
|
|
486
|
+
set: function (newValue) {
|
|
487
|
+
setValue.call(this, newValue);
|
|
472
488
|
for (const { afterSet } of hooksForKey) {
|
|
473
489
|
afterSet?.(newValue);
|
|
474
490
|
}
|
|
@@ -1369,7 +1385,7 @@ function useIsSectionEmpty(sectionId) {
|
|
|
1369
1385
|
return hasItems;
|
|
1370
1386
|
}
|
|
1371
1387
|
|
|
1372
|
-
const useStyles
|
|
1388
|
+
const useStyles$10 = makeStyles({
|
|
1373
1389
|
accordion: {
|
|
1374
1390
|
display: "flex",
|
|
1375
1391
|
flexDirection: "column",
|
|
@@ -1461,7 +1477,7 @@ const useStyles$$ = makeStyles({
|
|
|
1461
1477
|
*/
|
|
1462
1478
|
const AccordionMenuBar = () => {
|
|
1463
1479
|
AccordionMenuBar.displayName = "AccordionMenuBar";
|
|
1464
|
-
const classes = useStyles
|
|
1480
|
+
const classes = useStyles$10();
|
|
1465
1481
|
const accordionCtx = useContext(AccordionContext);
|
|
1466
1482
|
if (!accordionCtx) {
|
|
1467
1483
|
return null;
|
|
@@ -1485,7 +1501,7 @@ const AccordionMenuBar = () => {
|
|
|
1485
1501
|
const AccordionSectionBlock = (props) => {
|
|
1486
1502
|
AccordionSectionBlock.displayName = "AccordionSectionBlock";
|
|
1487
1503
|
const { children, sectionId } = props;
|
|
1488
|
-
const classes = useStyles
|
|
1504
|
+
const classes = useStyles$10();
|
|
1489
1505
|
const accordionCtx = useContext(AccordionContext);
|
|
1490
1506
|
const { context: sectionContext, isEmpty } = useAccordionSectionBlockContext(props);
|
|
1491
1507
|
if (accordionCtx) {
|
|
@@ -1505,7 +1521,7 @@ const AccordionSectionBlock = (props) => {
|
|
|
1505
1521
|
const AccordionSectionItem = (props) => {
|
|
1506
1522
|
AccordionSectionItem.displayName = "AccordionSectionItem";
|
|
1507
1523
|
const { children, staticItem } = props;
|
|
1508
|
-
const classes = useStyles
|
|
1524
|
+
const classes = useStyles$10();
|
|
1509
1525
|
const accordionCtx = useContext(AccordionContext);
|
|
1510
1526
|
const itemState = useAccordionSectionItemState(props);
|
|
1511
1527
|
const [ctrlMode, setCtrlMode] = useState(false);
|
|
@@ -1545,7 +1561,7 @@ const AccordionSectionItem = (props) => {
|
|
|
1545
1561
|
*/
|
|
1546
1562
|
const AccordionPinnedContainer = () => {
|
|
1547
1563
|
AccordionPinnedContainer.displayName = "AccordionPinnedContainer";
|
|
1548
|
-
const classes = useStyles
|
|
1564
|
+
const classes = useStyles$10();
|
|
1549
1565
|
const accordionCtx = useContext(AccordionContext);
|
|
1550
1566
|
return (jsx("div", { ref: accordionCtx?.pinnedContainerRef, className: classes.pinnedContainer, children: jsx(MessageBar$1, { className: classes.pinnedContainerEmpty, children: jsx(MessageBarBody, { children: "No pinned items" }) }) }));
|
|
1551
1567
|
};
|
|
@@ -1556,7 +1572,7 @@ const AccordionPinnedContainer = () => {
|
|
|
1556
1572
|
*/
|
|
1557
1573
|
const AccordionSearchBox = () => {
|
|
1558
1574
|
AccordionSearchBox.displayName = "AccordionSearchBox";
|
|
1559
|
-
const classes = useStyles
|
|
1575
|
+
const classes = useStyles$10();
|
|
1560
1576
|
const accordionCtx = useContext(AccordionContext);
|
|
1561
1577
|
if (!accordionCtx?.features.search) {
|
|
1562
1578
|
return null;
|
|
@@ -1572,7 +1588,7 @@ const AccordionSearchBox = () => {
|
|
|
1572
1588
|
*/
|
|
1573
1589
|
const AccordionSection = (props) => {
|
|
1574
1590
|
AccordionSection.displayName = "AccordionSection";
|
|
1575
|
-
const classes = useStyles
|
|
1591
|
+
const classes = useStyles$10();
|
|
1576
1592
|
return jsx("div", { className: classes.panelDiv, children: props.children });
|
|
1577
1593
|
};
|
|
1578
1594
|
const StringAccordion = Accordion$1;
|
|
@@ -1580,7 +1596,7 @@ const Accordion = forwardRef((props, ref) => {
|
|
|
1580
1596
|
Accordion.displayName = "Accordion";
|
|
1581
1597
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1582
1598
|
const { children, highlightSections, uniqueId, enablePinnedItems, enableHiddenItems, enableSearchItems, ...rest } = props;
|
|
1583
|
-
const classes = useStyles
|
|
1599
|
+
const classes = useStyles$10();
|
|
1584
1600
|
const { size } = useContext(ToolContext);
|
|
1585
1601
|
const accordionCtx = useAccordionContext(props);
|
|
1586
1602
|
const hasPinning = accordionCtx?.features.pinning ?? false;
|
|
@@ -1677,7 +1693,7 @@ const Collapse = (props) => {
|
|
|
1677
1693
|
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 }) }));
|
|
1678
1694
|
};
|
|
1679
1695
|
|
|
1680
|
-
const useStyles
|
|
1696
|
+
const useStyles$$ = makeStyles({
|
|
1681
1697
|
button: {
|
|
1682
1698
|
display: "flex",
|
|
1683
1699
|
alignItems: "center",
|
|
@@ -1693,9 +1709,9 @@ const useStyles$_ = makeStyles({
|
|
|
1693
1709
|
*/
|
|
1694
1710
|
const ToggleButton = (props) => {
|
|
1695
1711
|
ToggleButton.displayName = "ToggleButton";
|
|
1696
|
-
const { value, onChange, title, appearance = "subtle" } = props;
|
|
1712
|
+
const { value, onChange, title, appearance = "subtle", ariaLabel } = props;
|
|
1697
1713
|
const { size } = useContext(ToolContext);
|
|
1698
|
-
const classes = useStyles
|
|
1714
|
+
const classes = useStyles$$();
|
|
1699
1715
|
const [checked, setChecked] = useState(value);
|
|
1700
1716
|
const toggle = useCallback(() => {
|
|
1701
1717
|
setChecked((prevChecked) => {
|
|
@@ -1707,7 +1723,7 @@ const ToggleButton = (props) => {
|
|
|
1707
1723
|
useEffect(() => {
|
|
1708
1724
|
setChecked(props.value);
|
|
1709
1725
|
}, [props.value]);
|
|
1710
|
-
return (jsx(Tooltip, { content: title ?? "", children: jsx(ToggleButton$1, { className: classes.button, size: size, icon: checked ? jsx(props.checkedIcon, {}) : props.uncheckedIcon ? jsx(props.uncheckedIcon, {}) : jsx(props.checkedIcon, {}), appearance: appearance, checked: checked, onClick: toggle }) }));
|
|
1726
|
+
return (jsx(Tooltip, { content: title ?? "", positioning: props.titlePositioning, children: jsx(ToggleButton$1, { className: classes.button, size: size, "aria-label": ariaLabel ?? title, icon: checked ? jsx(props.checkedIcon, {}) : props.uncheckedIcon ? jsx(props.uncheckedIcon, {}) : jsx(props.checkedIcon, {}), appearance: appearance, checked: checked, onClick: toggle }) }));
|
|
1711
1727
|
};
|
|
1712
1728
|
|
|
1713
1729
|
const useInfoLabelStyles = makeStyles({
|
|
@@ -2004,7 +2020,7 @@ const UXContextProvider = (props) => {
|
|
|
2004
2020
|
function AsReadonlyArray(array) {
|
|
2005
2021
|
return array;
|
|
2006
2022
|
}
|
|
2007
|
-
const useStyles$
|
|
2023
|
+
const useStyles$_ = makeStyles({
|
|
2008
2024
|
rootDiv: {
|
|
2009
2025
|
flex: 1,
|
|
2010
2026
|
overflow: "hidden",
|
|
@@ -2019,7 +2035,7 @@ const useStyles$Z = makeStyles({
|
|
|
2019
2035
|
* @returns The extensible accordion component.
|
|
2020
2036
|
*/
|
|
2021
2037
|
function ExtensibleAccordion(props) {
|
|
2022
|
-
const classes = useStyles$
|
|
2038
|
+
const classes = useStyles$_();
|
|
2023
2039
|
const { children, sections, sectionContent, context, sectionsRef, ...rest } = props;
|
|
2024
2040
|
const defaultSections = useMemo(() => {
|
|
2025
2041
|
const defaultSections = [];
|
|
@@ -2144,7 +2160,7 @@ function ExtensibleAccordion(props) {
|
|
|
2144
2160
|
})] }) })) }));
|
|
2145
2161
|
}
|
|
2146
2162
|
|
|
2147
|
-
const useStyles$
|
|
2163
|
+
const useStyles$Z = makeStyles({
|
|
2148
2164
|
paneRootDiv: {
|
|
2149
2165
|
display: "flex",
|
|
2150
2166
|
flex: 1,
|
|
@@ -2157,7 +2173,7 @@ const useStyles$Y = makeStyles({
|
|
|
2157
2173
|
*/
|
|
2158
2174
|
const SidePaneContainer = forwardRef((props, ref) => {
|
|
2159
2175
|
const { className, ...rest } = props;
|
|
2160
|
-
const classes = useStyles$
|
|
2176
|
+
const classes = useStyles$Z();
|
|
2161
2177
|
return (jsx("div", { className: mergeClasses(classes.paneRootDiv, className), ref: ref, ...rest, children: props.children }));
|
|
2162
2178
|
});
|
|
2163
2179
|
|
|
@@ -2428,7 +2444,7 @@ function useTheme(invert = false) {
|
|
|
2428
2444
|
}
|
|
2429
2445
|
|
|
2430
2446
|
// Fluent doesn't apply styling to scrollbars by default, so provide our own reasonable default.
|
|
2431
|
-
const useStyles$
|
|
2447
|
+
const useStyles$Y = makeStyles({
|
|
2432
2448
|
root: {
|
|
2433
2449
|
scrollbarColor: `${tokens.colorNeutralForeground3} ${tokens.colorTransparentBackground}`,
|
|
2434
2450
|
},
|
|
@@ -2436,19 +2452,42 @@ const useStyles$X = makeStyles({
|
|
|
2436
2452
|
/**
|
|
2437
2453
|
* A themed Fluent UI provider that applies the current theme mode (light or dark).
|
|
2438
2454
|
* @param props Fluent provider props, plus an optional `invert` flag to swap the theme.
|
|
2455
|
+
* When `targetDocument` is provided and differs from the inherited Fluent
|
|
2456
|
+
* document (e.g. when rendering into a popup window), a Griffel renderer
|
|
2457
|
+
* scoped to that document is created so styles are injected into it.
|
|
2458
|
+
* When omitted, `targetDocument` is inherited from the ambient Fluent
|
|
2459
|
+
* context so nested Theme components do not lose cross-window targeting.
|
|
2439
2460
|
* @returns The themed Fluent UI provider component.
|
|
2440
2461
|
*/
|
|
2441
2462
|
const Theme = (props) => {
|
|
2442
2463
|
// NOTE: We do not want to applyStylesToPortals by default. It makes classes flow into portals
|
|
2443
2464
|
// (like popovers), and if those styles do things like disable overflow, they can completely
|
|
2444
2465
|
// break any UI within the portal. Therefore, default to false.
|
|
2445
|
-
const { invert = false, applyStylesToPortals = false, className, ...rest } = props;
|
|
2466
|
+
const { invert = false, applyStylesToPortals = false, className, targetDocument: explicitTargetDocument, ...rest } = props;
|
|
2446
2467
|
const theme = useTheme(invert);
|
|
2447
|
-
const classes = useStyles$
|
|
2448
|
-
|
|
2468
|
+
const classes = useStyles$Y();
|
|
2469
|
+
// Resolve the target document from the explicit prop or fall back to the ambient Fluent context.
|
|
2470
|
+
// This makes nested <Theme> components automatically inherit cross-window targeting from a
|
|
2471
|
+
// top-level <Theme targetDocument={popupDocument}> wrapper.
|
|
2472
|
+
const inheritedTargetDocument = useFluent().targetDocument;
|
|
2473
|
+
const resolvedTargetDocument = explicitTargetDocument ?? inheritedTargetDocument;
|
|
2474
|
+
// Only create a new Griffel renderer when the resolved document differs from the inherited
|
|
2475
|
+
// one. In the common (main-window, no nesting) case, this leaves Fluent's default renderer
|
|
2476
|
+
// and renderer provider in place — matching the original behaviour exactly.
|
|
2477
|
+
const renderer = useMemo(() => {
|
|
2478
|
+
if (resolvedTargetDocument && resolvedTargetDocument !== inheritedTargetDocument) {
|
|
2479
|
+
return createDOMRenderer(resolvedTargetDocument);
|
|
2480
|
+
}
|
|
2481
|
+
return undefined;
|
|
2482
|
+
}, [resolvedTargetDocument, inheritedTargetDocument]);
|
|
2483
|
+
const fluent = (jsx(FluentProvider, { theme: theme, className: mergeClasses(classes.root, className), applyStylesToPortals: applyStylesToPortals, targetDocument: resolvedTargetDocument, ...rest, children: props.children }));
|
|
2484
|
+
if (renderer && resolvedTargetDocument) {
|
|
2485
|
+
return (jsx(RendererProvider, { renderer: renderer, targetDocument: resolvedTargetDocument, children: fluent }));
|
|
2486
|
+
}
|
|
2487
|
+
return fluent;
|
|
2449
2488
|
};
|
|
2450
2489
|
|
|
2451
|
-
const useStyles$
|
|
2490
|
+
const useStyles$X = makeStyles({
|
|
2452
2491
|
extensionTeachingPopover: {
|
|
2453
2492
|
maxWidth: "320px",
|
|
2454
2493
|
},
|
|
@@ -2459,7 +2498,7 @@ const useStyles$W = makeStyles({
|
|
|
2459
2498
|
* @returns The teaching moment popover.
|
|
2460
2499
|
*/
|
|
2461
2500
|
const TeachingMoment = ({ shouldDisplay, positioningRef, onOpenChange, title, description }) => {
|
|
2462
|
-
const classes = useStyles$
|
|
2501
|
+
const classes = useStyles$X();
|
|
2463
2502
|
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 })] }) }));
|
|
2464
2503
|
};
|
|
2465
2504
|
|
|
@@ -2684,24 +2723,161 @@ function ConstructorFactory(constructor) {
|
|
|
2684
2723
|
return (...args) => new constructor(...args);
|
|
2685
2724
|
}
|
|
2686
2725
|
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
const
|
|
2690
|
-
if (
|
|
2691
|
-
|
|
2726
|
+
const StorageKeyPrefix = "Babylon/Settings/PopupWindow";
|
|
2727
|
+
function LoadSavedBounds(id) {
|
|
2728
|
+
const stored = localStorage.getItem(`${StorageKeyPrefix}/${id}/Bounds`);
|
|
2729
|
+
if (!stored) {
|
|
2730
|
+
return null;
|
|
2731
|
+
}
|
|
2732
|
+
try {
|
|
2733
|
+
const parsed = JSON.parse(stored);
|
|
2734
|
+
return parsed;
|
|
2735
|
+
}
|
|
2736
|
+
catch {
|
|
2737
|
+
Logger.Warn(`Could not parse saved bounds for popup window with id ${id}`);
|
|
2738
|
+
return null;
|
|
2692
2739
|
}
|
|
2693
|
-
|
|
2694
|
-
|
|
2740
|
+
}
|
|
2741
|
+
function SaveBounds(id, bounds) {
|
|
2742
|
+
try {
|
|
2743
|
+
localStorage.setItem(`${StorageKeyPrefix}/${id}/Bounds`, JSON.stringify(bounds));
|
|
2695
2744
|
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2745
|
+
catch {
|
|
2746
|
+
// Storage may be full / disabled — bounds simply won't persist.
|
|
2698
2747
|
}
|
|
2699
|
-
|
|
2700
|
-
|
|
2748
|
+
}
|
|
2749
|
+
function ResolveBounds(options) {
|
|
2750
|
+
const saved = options.id ? LoadSavedBounds(options.id) : null;
|
|
2751
|
+
const width = options.defaultWidth ?? saved?.width ?? Math.floor(window.innerWidth * (2 / 3));
|
|
2752
|
+
const height = options.defaultHeight ?? saved?.height ?? Math.floor(window.innerHeight * (2 / 3));
|
|
2753
|
+
const left = options.defaultLeft ?? saved?.left ?? Math.floor(window.screenX + (window.innerWidth - width) / 2);
|
|
2754
|
+
const top = options.defaultTop ?? saved?.top ?? Math.floor(window.screenY + (window.innerHeight - height) / 2);
|
|
2755
|
+
// When the caller passes explicit width/height/left/top, always honour them; otherwise fall
|
|
2756
|
+
// back to the (saved or computed) values above. The order above already gives explicit
|
|
2757
|
+
// options precedence, so just build the resulting bounds now.
|
|
2758
|
+
return { left, top, width, height };
|
|
2759
|
+
}
|
|
2760
|
+
function ToFeaturesString(bounds) {
|
|
2761
|
+
return `width=${bounds.width},height=${bounds.height},left=${bounds.left},top=${bounds.top},location=no`;
|
|
2762
|
+
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Opens a new browser popup window suitable for hosting a Fluent-based modular tool.
|
|
2765
|
+
*
|
|
2766
|
+
* The popup body is configured for full-bleed flex layout and a host `<div>` is appended
|
|
2767
|
+
* for the tool to render into. Fluent style targeting (Griffel `RendererProvider`,
|
|
2768
|
+
* `FluentProvider` with `targetDocument`) is the caller's responsibility — typically wired
|
|
2769
|
+
* up by `MakeModularTool`, which derives `targetDocument` from `containerElement.ownerDocument`.
|
|
2770
|
+
*
|
|
2771
|
+
* **Must be called synchronously in response to a user interaction** (e.g. button click) —
|
|
2772
|
+
* otherwise the browser will block the popup as a scripted popup.
|
|
2773
|
+
*
|
|
2774
|
+
* @param options Window options. See {@link PopupWindowOptions}.
|
|
2775
|
+
* @returns A handle to the popup window and its host element, plus a `dispose` to close it.
|
|
2776
|
+
* `null` if the popup was blocked by the browser.
|
|
2777
|
+
*/
|
|
2778
|
+
function OpenPopupWindow(options = {}) {
|
|
2779
|
+
const bounds = ResolveBounds(options);
|
|
2780
|
+
const popupWindow = window.open("", "", ToFeaturesString(bounds));
|
|
2781
|
+
if (!popupWindow) {
|
|
2782
|
+
return null;
|
|
2701
2783
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2784
|
+
if (options.title) {
|
|
2785
|
+
popupWindow.document.title = options.title;
|
|
2786
|
+
}
|
|
2787
|
+
const popupBody = popupWindow.document.body;
|
|
2788
|
+
popupBody.style.width = "100%";
|
|
2789
|
+
popupBody.style.height = "100%";
|
|
2790
|
+
popupBody.style.margin = "0";
|
|
2791
|
+
popupBody.style.padding = "0";
|
|
2792
|
+
popupBody.style.display = "flex";
|
|
2793
|
+
popupBody.style.overflow = "hidden";
|
|
2794
|
+
const hostElement = popupWindow.document.createElement("div");
|
|
2795
|
+
hostElement.style.display = "flex";
|
|
2796
|
+
hostElement.style.flexDirection = "column";
|
|
2797
|
+
hostElement.style.flexGrow = "1";
|
|
2798
|
+
hostElement.style.width = "100%";
|
|
2799
|
+
hostElement.style.height = "100%";
|
|
2800
|
+
hostElement.style.margin = "0";
|
|
2801
|
+
hostElement.style.padding = "0";
|
|
2802
|
+
hostElement.style.overflow = "hidden";
|
|
2803
|
+
popupBody.appendChild(hostElement);
|
|
2804
|
+
// Track the most recently observed window bounds. In some browsers (e.g. Firefox), accessing
|
|
2805
|
+
// properties like screenX on a closed window throws, so we cache the last known good values
|
|
2806
|
+
// to use as a fallback when saving after the window has already been closed.
|
|
2807
|
+
const getBounds = () => ({
|
|
2808
|
+
left: popupWindow.screenX,
|
|
2809
|
+
top: popupWindow.screenY,
|
|
2810
|
+
width: popupWindow.innerWidth,
|
|
2811
|
+
height: popupWindow.innerHeight,
|
|
2812
|
+
});
|
|
2813
|
+
let lastBounds = bounds;
|
|
2814
|
+
const onPopupBeforeUnload = () => {
|
|
2815
|
+
try {
|
|
2816
|
+
lastBounds = getBounds();
|
|
2817
|
+
}
|
|
2818
|
+
catch {
|
|
2819
|
+
// Use the cached lastBounds.
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
popupWindow.addEventListener("beforeunload", onPopupBeforeUnload);
|
|
2823
|
+
let disposed = false;
|
|
2824
|
+
// Internal cleanup: tears down listeners, persists bounds, closes the popup.
|
|
2825
|
+
// Does NOT invoke `options.onClose` — that's reserved for popup unload events
|
|
2826
|
+
// that originate from outside our own teardown (e.g. user dismissed the popup).
|
|
2827
|
+
const cleanup = () => {
|
|
2828
|
+
if (disposed) {
|
|
2829
|
+
return;
|
|
2830
|
+
}
|
|
2831
|
+
disposed = true;
|
|
2832
|
+
if (options.id) {
|
|
2833
|
+
try {
|
|
2834
|
+
if (!popupWindow.closed) {
|
|
2835
|
+
lastBounds = getBounds();
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
catch {
|
|
2839
|
+
// Use the cached lastBounds.
|
|
2840
|
+
}
|
|
2841
|
+
SaveBounds(options.id, lastBounds);
|
|
2842
|
+
}
|
|
2843
|
+
popupWindow.removeEventListener("beforeunload", onPopupBeforeUnload);
|
|
2844
|
+
// Remove the unload listener so that any pending unload event triggered by our
|
|
2845
|
+
// own popupWindow.close() below cannot reach back into onPopupUnload after we've
|
|
2846
|
+
// already torn down. This avoids a race where, during a programmatic open-while-open
|
|
2847
|
+
// swap, the old popup's unload would otherwise fire onClose and clear React state
|
|
2848
|
+
// pointing at the new popup.
|
|
2849
|
+
popupWindow.removeEventListener("unload", onPopupUnload);
|
|
2850
|
+
window.removeEventListener("unload", onParentUnload);
|
|
2851
|
+
if (!popupWindow.closed) {
|
|
2852
|
+
popupWindow.close();
|
|
2853
|
+
}
|
|
2854
|
+
};
|
|
2855
|
+
const onPopupUnload = () => {
|
|
2856
|
+
if (disposed) {
|
|
2857
|
+
// Already torn down programmatically; the popup is just finishing its unload.
|
|
2858
|
+
return;
|
|
2859
|
+
}
|
|
2860
|
+
cleanup();
|
|
2861
|
+
// Notify the consumer only for externally-triggered closures (user dismissed the popup,
|
|
2862
|
+
// tab/browser closed). Programmatic disposal calls cleanup() directly and intentionally
|
|
2863
|
+
// skips this so callers don't get a re-entrant onClose for the close they themselves issued.
|
|
2864
|
+
options.onClose?.();
|
|
2865
|
+
};
|
|
2866
|
+
popupWindow.addEventListener("unload", onPopupUnload, { once: true });
|
|
2867
|
+
// If the parent window is unloaded (page refresh / navigation), don't leave the popup orphaned.
|
|
2868
|
+
const onParentUnload = () => {
|
|
2869
|
+
if (!popupWindow.closed) {
|
|
2870
|
+
popupWindow.close();
|
|
2871
|
+
}
|
|
2872
|
+
};
|
|
2873
|
+
window.addEventListener("unload", onParentUnload, { once: true });
|
|
2874
|
+
return {
|
|
2875
|
+
popupWindow,
|
|
2876
|
+
hostElement,
|
|
2877
|
+
dispose: cleanup,
|
|
2878
|
+
};
|
|
2704
2879
|
}
|
|
2880
|
+
|
|
2705
2881
|
/**
|
|
2706
2882
|
* Allows displaying a child window that can contain child components.
|
|
2707
2883
|
* @param props Props for the child window.
|
|
@@ -2710,133 +2886,66 @@ function ToFeaturesString(options) {
|
|
|
2710
2886
|
const ChildWindow = (props) => {
|
|
2711
2887
|
const { id, children, onOpenChange, imperativeRef: imperativeRef } = props;
|
|
2712
2888
|
const [windowState, setWindowState] = useState();
|
|
2713
|
-
const [
|
|
2714
|
-
const storageKey = id ? `Babylon/Settings/ChildWindow/${id}/Bounds` : null;
|
|
2889
|
+
const [popupHandle, setPopupHandle] = useState();
|
|
2715
2890
|
// This function is just for creating the child window itself. It is a function because
|
|
2716
2891
|
// it must be called synchronously in response to a user interaction (e.g. button click),
|
|
2717
2892
|
// otherwise the browser will block it as a scripted popup.
|
|
2718
2893
|
const createWindow = useCallback((options = {}) => {
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
// Half width by default.
|
|
2745
|
-
if (!options.defaultWidth) {
|
|
2746
|
-
options.defaultWidth = window.innerWidth * (2 / 3);
|
|
2747
|
-
}
|
|
2748
|
-
// Half height by default.
|
|
2749
|
-
if (!options.defaultHeight) {
|
|
2750
|
-
options.defaultHeight = window.innerHeight * (2 / 3);
|
|
2751
|
-
}
|
|
2752
|
-
// Horizontally centered by default.
|
|
2753
|
-
if (!options.defaultLeft) {
|
|
2754
|
-
options.defaultLeft = window.screenX + (window.innerWidth - options.defaultWidth) * (2 / 3);
|
|
2755
|
-
}
|
|
2756
|
-
// Vertically centered by default.
|
|
2757
|
-
if (!options.defaultTop) {
|
|
2758
|
-
options.defaultTop = window.screenY + (window.innerHeight - options.defaultHeight) * (2 / 3);
|
|
2759
|
-
}
|
|
2760
|
-
// Try to create the child window (can be null if popups are blocked).
|
|
2761
|
-
const newChildWindow = window.open("", "", ToFeaturesString(options));
|
|
2762
|
-
if (newChildWindow) {
|
|
2763
|
-
// Set the title if provided.
|
|
2764
|
-
newChildWindow.document.title = options.title ?? id ?? "";
|
|
2765
|
-
// Set the child window state.
|
|
2766
|
-
setChildWindow((current) => {
|
|
2767
|
-
// But first close any existing child window.
|
|
2768
|
-
current?.close();
|
|
2769
|
-
return newChildWindow;
|
|
2894
|
+
const handle = OpenPopupWindow({
|
|
2895
|
+
id,
|
|
2896
|
+
title: options.title ?? id,
|
|
2897
|
+
defaultWidth: options.defaultWidth,
|
|
2898
|
+
defaultHeight: options.defaultHeight,
|
|
2899
|
+
defaultLeft: options.defaultLeft,
|
|
2900
|
+
defaultTop: options.defaultTop,
|
|
2901
|
+
onClose: () => {
|
|
2902
|
+
// Triggered when the popup is closed for any reason (user dismissal, parent unload,
|
|
2903
|
+
// or programmatic dispose). Clear the popup handle so the effect cleanup runs and
|
|
2904
|
+
// `onOpenChange(false)` is propagated up the tree (which lets a parent shell re-dock
|
|
2905
|
+
// a previously-undocked pane). teardown() is idempotent so calling dispose() again
|
|
2906
|
+
// from the effect cleanup is a safe no-op.
|
|
2907
|
+
setPopupHandle(undefined);
|
|
2908
|
+
},
|
|
2909
|
+
});
|
|
2910
|
+
if (handle) {
|
|
2911
|
+
setPopupHandle((current) => {
|
|
2912
|
+
// Close any existing child window before adopting the new one.
|
|
2913
|
+
current?.dispose();
|
|
2914
|
+
return handle;
|
|
2770
2915
|
});
|
|
2771
2916
|
}
|
|
2772
|
-
}, [
|
|
2917
|
+
}, [id]);
|
|
2773
2918
|
useImperativeHandle(imperativeRef, () => {
|
|
2774
2919
|
return {
|
|
2775
2920
|
open: createWindow,
|
|
2776
|
-
close: () =>
|
|
2921
|
+
close: () => {
|
|
2922
|
+
setPopupHandle((current) => {
|
|
2923
|
+
current?.dispose();
|
|
2924
|
+
return undefined;
|
|
2925
|
+
});
|
|
2926
|
+
},
|
|
2777
2927
|
};
|
|
2778
2928
|
}, [createWindow]);
|
|
2779
|
-
// This side effect runs any time the
|
|
2929
|
+
// This side effect runs any time the popup handle changes. It does the rest of the child window
|
|
2780
2930
|
// setup work, including creating resources and state needed to properly render the content of the child window.
|
|
2781
2931
|
useEffect(() => {
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
const body = childWindow.document.body;
|
|
2785
|
-
body.style.width = "100%";
|
|
2786
|
-
body.style.height = "100%";
|
|
2787
|
-
body.style.margin = "0";
|
|
2788
|
-
body.style.padding = "0";
|
|
2789
|
-
body.style.display = "flex";
|
|
2790
|
-
body.style.overflow = "hidden";
|
|
2791
|
-
// Setup the window state, including creating a Fluent/Griffel "renderer" for managing runtime styles/classes in the child window.
|
|
2792
|
-
setWindowState({ mountNode: body, renderer: createDOMRenderer(childWindow.document) });
|
|
2793
|
-
onOpenChange?.(true);
|
|
2794
|
-
// Track the most recently observed window bounds. In some browsers (e.g. Firefox), accessing
|
|
2795
|
-
// properties like screenX on a closed window throws, so we cache the last known good values
|
|
2796
|
-
// to use as a fallback when the dispose runs after the window has already been closed.
|
|
2797
|
-
const getBounds = () => ({
|
|
2798
|
-
left: childWindow.screenX,
|
|
2799
|
-
top: childWindow.screenY,
|
|
2800
|
-
width: childWindow.innerWidth,
|
|
2801
|
-
height: childWindow.innerHeight,
|
|
2802
|
-
});
|
|
2803
|
-
let lastBounds = getBounds();
|
|
2804
|
-
// When the child window is closed for any reason, transition back to a closed state.
|
|
2805
|
-
const onChildWindowUnload = () => {
|
|
2806
|
-
setWindowState(undefined);
|
|
2807
|
-
setChildWindow(undefined);
|
|
2808
|
-
onOpenChange?.(false);
|
|
2809
|
-
};
|
|
2810
|
-
childWindow.addEventListener("unload", onChildWindowUnload, { once: true });
|
|
2811
|
-
disposeActions.push(() => childWindow.removeEventListener("unload", onChildWindowUnload));
|
|
2812
|
-
// Capture bounds before the window is unloaded, while its properties are still safe to read.
|
|
2813
|
-
const onChildWindowBeforeUnload = () => {
|
|
2814
|
-
lastBounds = getBounds();
|
|
2815
|
-
};
|
|
2816
|
-
childWindow.addEventListener("beforeunload", onChildWindowBeforeUnload);
|
|
2817
|
-
disposeActions.push(() => childWindow.removeEventListener("beforeunload", onChildWindowBeforeUnload));
|
|
2818
|
-
// If the main window closes, close any open child windows as well (don't leave them orphaned).
|
|
2819
|
-
const onParentWindowUnload = () => {
|
|
2820
|
-
childWindow.close();
|
|
2821
|
-
};
|
|
2822
|
-
window.addEventListener("unload", onParentWindowUnload, { once: true });
|
|
2823
|
-
disposeActions.push(() => window.removeEventListener("unload", onParentWindowUnload));
|
|
2824
|
-
// On dispose, close the child window.
|
|
2825
|
-
disposeActions.push(() => childWindow.close());
|
|
2826
|
-
// On dispose, save the window bounds.
|
|
2827
|
-
disposeActions.push(() => {
|
|
2828
|
-
if (storageKey) {
|
|
2829
|
-
if (!childWindow.closed) {
|
|
2830
|
-
lastBounds = getBounds();
|
|
2831
|
-
}
|
|
2832
|
-
localStorage.setItem(storageKey, JSON.stringify(lastBounds));
|
|
2833
|
-
}
|
|
2834
|
-
});
|
|
2932
|
+
if (!popupHandle) {
|
|
2933
|
+
return undefined;
|
|
2835
2934
|
}
|
|
2935
|
+
const popupDocument = popupHandle.popupWindow.document;
|
|
2936
|
+
// Use the popup's hostElement as the React mount point. OpenPopupWindow configures it as a
|
|
2937
|
+
// flex column that fills the popup body, so the FluentProvider (also a flex column with
|
|
2938
|
+
// flex-grow: 1) inside it can fill the available space.
|
|
2939
|
+
setWindowState({ mountNode: popupHandle.hostElement, renderer: createDOMRenderer(popupDocument) });
|
|
2940
|
+
onOpenChange?.(true);
|
|
2836
2941
|
return () => {
|
|
2837
|
-
|
|
2942
|
+
// Tear down the popup. The cached handle's dispose() handles bounds saving and
|
|
2943
|
+
// listener cleanup; React state is reset so the Portal/Provider tree unmounts.
|
|
2944
|
+
popupHandle.dispose();
|
|
2945
|
+
setWindowState(undefined);
|
|
2946
|
+
onOpenChange?.(false);
|
|
2838
2947
|
};
|
|
2839
|
-
}, [
|
|
2948
|
+
}, [popupHandle]);
|
|
2840
2949
|
if (!windowState) {
|
|
2841
2950
|
return null;
|
|
2842
2951
|
}
|
|
@@ -2892,7 +3001,7 @@ const RootComponentServiceIdentity = Symbol("RootComponent");
|
|
|
2892
3001
|
* The unique identity symbol for the shell service.
|
|
2893
3002
|
*/
|
|
2894
3003
|
const ShellServiceIdentity = Symbol("ShellService");
|
|
2895
|
-
const useStyles$
|
|
3004
|
+
const useStyles$W = makeStyles({
|
|
2896
3005
|
mainView: {
|
|
2897
3006
|
flex: 1,
|
|
2898
3007
|
display: "flex",
|
|
@@ -2959,6 +3068,7 @@ const useStyles$V = makeStyles({
|
|
|
2959
3068
|
paneCollapseButton: {
|
|
2960
3069
|
padding: `0 0 0 ${tokens.spacingHorizontalXS}`,
|
|
2961
3070
|
borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
|
|
3071
|
+
backgroundColor: tokens.colorNeutralBackground2,
|
|
2962
3072
|
},
|
|
2963
3073
|
paneCollapseButtonWithBorder: {
|
|
2964
3074
|
borderLeft: `1px solid ${tokens.colorNeutralStroke2}`,
|
|
@@ -2982,6 +3092,11 @@ const useStyles$V = makeStyles({
|
|
|
2982
3092
|
paneContainer: {
|
|
2983
3093
|
display: "flex",
|
|
2984
3094
|
flexDirection: "column",
|
|
3095
|
+
// Side panes hold the width requested by their `style.width` (or saved/dragged value)
|
|
3096
|
+
// and never give it up to a neighboring pane growing. Without this, dragging the left
|
|
3097
|
+
// pane wider would also squeeze the right pane (proportional flex-shrink). The central
|
|
3098
|
+
// content (`flex-grow: 1`) is the only flex item that absorbs the change.
|
|
3099
|
+
flexShrink: 0,
|
|
2985
3100
|
overflowX: "hidden",
|
|
2986
3101
|
overflowY: "hidden",
|
|
2987
3102
|
zIndex: 1,
|
|
@@ -3105,14 +3220,14 @@ const DockMenu = (props) => {
|
|
|
3105
3220
|
};
|
|
3106
3221
|
const PaneHeader = (props) => {
|
|
3107
3222
|
const { id, title, dockOptions } = props;
|
|
3108
|
-
const classes = useStyles$
|
|
3223
|
+
const classes = useStyles$W();
|
|
3109
3224
|
return (jsxs("div", { className: classes.paneHeaderDiv, children: [props.icon && (jsx("div", { className: classes.paneHeaderIcon, children: jsx(props.icon, {}) })), jsx(Subtitle2Stronger, { className: mergeClasses(classes.paneHeaderText, !props.icon && classes.paneHeaderTextNoIcon), children: title }), jsx(DockMenu, { sidePaneId: id, dockOptions: dockOptions, children: jsx(Button$1, { className: classes.paneHeaderButton, appearance: "transparent", icon: jsx(MoreHorizontalRegular, {}) }) })] }));
|
|
3110
3225
|
};
|
|
3111
3226
|
// 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.
|
|
3112
3227
|
const ToolbarItem = (props) => {
|
|
3113
3228
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3114
3229
|
const { verticalLocation, horizontalLocation, id, component: Component, displayName } = props;
|
|
3115
|
-
const classes = useStyles$
|
|
3230
|
+
const classes = useStyles$W();
|
|
3116
3231
|
const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Bar/${verticalLocation}/${horizontalLocation}/${displayName ?? id}`), [displayName, id]);
|
|
3117
3232
|
const teachingMoment = useTeachingMoment(props.teachingMoment === false);
|
|
3118
3233
|
const title = typeof props.teachingMoment === "object" ? props.teachingMoment.title : (displayName ?? id);
|
|
@@ -3122,7 +3237,7 @@ const ToolbarItem = (props) => {
|
|
|
3122
3237
|
// TODO: Handle overflow, possibly via https://react.fluentui.dev/?path=/docs/components-overflow--docs with priority.
|
|
3123
3238
|
// This component just renders a toolbar with left aligned toolbar items on the left and right aligned toolbar items on the right.
|
|
3124
3239
|
const Toolbar = ({ location, components }) => {
|
|
3125
|
-
const classes = useStyles$
|
|
3240
|
+
const classes = useStyles$W();
|
|
3126
3241
|
const leftComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "left"), [components]);
|
|
3127
3242
|
const rightComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "right"), [components]);
|
|
3128
3243
|
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))) })] })) }));
|
|
@@ -3132,7 +3247,7 @@ const SidePaneTab = (props) => {
|
|
|
3132
3247
|
const { location, id, isSelected, isFirst, isLast, dockOptions,
|
|
3133
3248
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3134
3249
|
icon: Icon, title, } = props;
|
|
3135
|
-
const classes = useStyles$
|
|
3250
|
+
const classes = useStyles$W();
|
|
3136
3251
|
const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Pane/${location}/${title ?? id}`), [title, id]);
|
|
3137
3252
|
const teachingMoment = useTeachingMoment(props.teachingMoment === false);
|
|
3138
3253
|
const tabClass = mergeClasses(classes.tab, isSelected ? classes.selectedTab : classes.unselectedTab, isFirst ? classes.firstTab : undefined, isLast ? classes.lastTab : undefined);
|
|
@@ -3144,7 +3259,7 @@ const SidePaneTab = (props) => {
|
|
|
3144
3259
|
// In "compact" mode, the tab list is integrated into the pane itself.
|
|
3145
3260
|
// In "full" mode, the returned tab list is later injected into the toolbar.
|
|
3146
3261
|
function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane, dockOperations, toolbarMode, topBarItems, bottomBarItems, initialCollapsed) {
|
|
3147
|
-
const classes = useStyles$
|
|
3262
|
+
const classes = useStyles$W();
|
|
3148
3263
|
const [topSelectedTab, setTopSelectedTab] = useState();
|
|
3149
3264
|
const [bottomSelectedTab, setBottomSelectedTab] = useState();
|
|
3150
3265
|
const [collapsed, setCollapsed] = useState(initialCollapsed);
|
|
@@ -3293,16 +3408,25 @@ function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane,
|
|
|
3293
3408
|
// registered). The Fluent hook's setValue will silently fail when the element doesn't exist (in relative mode,
|
|
3294
3409
|
// it measures the element before/after and reverts if unchanged, which always happens when the element is null).
|
|
3295
3410
|
// By composing the ref callback, we ensure the stored value is applied immediately after the element mounts.
|
|
3411
|
+
//
|
|
3412
|
+
// We also set the CSS variable directly as a fallback. The hook preserves its internal currentValue across
|
|
3413
|
+
// re-mounts, so when (for example) the user undocks a resized pane and then re-docks it, currentValue already
|
|
3414
|
+
// equals the persisted setting and the hook's setValue short-circuits — but the freshly-mounted DOM node has no
|
|
3415
|
+
// inline CSS variable, so the pane visually reverts to the default width until the user drags. Setting the
|
|
3416
|
+
// variable directly closes that gap. The order is important: setValue first (handles the first-mount case where
|
|
3417
|
+
// currentValue starts at 0), then the direct setProperty as a redundant fallback for the no-op case.
|
|
3296
3418
|
const composedHorizontalElementRef = useCallback((node) => {
|
|
3297
3419
|
paneHorizontalResizeElementRef(node);
|
|
3298
3420
|
if (node) {
|
|
3299
3421
|
setPaneWidthAdjust(paneWidthSettingRef.current);
|
|
3422
|
+
node.style.setProperty(paneWidthAdjustCSSVar, `${paneWidthSettingRef.current}px`);
|
|
3300
3423
|
}
|
|
3301
3424
|
}, [paneHorizontalResizeElementRef, setPaneWidthAdjust]);
|
|
3302
3425
|
const composedVerticalElementRef = useCallback((node) => {
|
|
3303
3426
|
paneVerticalResizeElementRef(node);
|
|
3304
3427
|
if (node) {
|
|
3305
3428
|
setPaneHeightAdjust(paneHeightSettingRef.current);
|
|
3429
|
+
node.style.setProperty(paneHeightAdjustCSSVar, `${paneHeightSettingRef.current}px`);
|
|
3306
3430
|
}
|
|
3307
3431
|
}, [paneVerticalResizeElementRef, setPaneHeightAdjust]);
|
|
3308
3432
|
// Handle external setting changes (e.g. settings reset) after elements are already mounted.
|
|
@@ -3373,7 +3497,7 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
|
|
|
3373
3497
|
expand: () => onCollapseChanged.notifyObservers({ location: "right", collapsed: false }),
|
|
3374
3498
|
};
|
|
3375
3499
|
const rootComponent = () => {
|
|
3376
|
-
const classes = useStyles$
|
|
3500
|
+
const classes = useStyles$W();
|
|
3377
3501
|
const [sidePaneDockOverrides, setSidePaneDockOverrides] = useSetting(SidePaneDockOverridesSettingDescriptor);
|
|
3378
3502
|
// This function returns a promise that resolves after the dock change takes effect so that
|
|
3379
3503
|
// we can then select the re-docked pane.
|
|
@@ -3760,13 +3884,13 @@ function useImpulse() {
|
|
|
3760
3884
|
return [value, pulse];
|
|
3761
3885
|
}
|
|
3762
3886
|
|
|
3763
|
-
const useStyles$
|
|
3887
|
+
const useStyles$V = makeStyles({
|
|
3764
3888
|
placeholderDiv: {
|
|
3765
3889
|
padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
|
|
3766
3890
|
},
|
|
3767
3891
|
});
|
|
3768
3892
|
const PropertiesPane = (props) => {
|
|
3769
|
-
const classes = useStyles$
|
|
3893
|
+
const classes = useStyles$V();
|
|
3770
3894
|
const entity = props.context;
|
|
3771
3895
|
return entity != null ? (jsx(ExtensibleAccordion, { ...props })) : (jsx("div", { className: classes.placeholderDiv, children: jsx(Body1Strong, { italic: true, children: "No entity selected." }) }));
|
|
3772
3896
|
};
|
|
@@ -4206,7 +4330,7 @@ function CoerceEntityArray(entities, sort) {
|
|
|
4206
4330
|
}
|
|
4207
4331
|
return entities;
|
|
4208
4332
|
}
|
|
4209
|
-
const useStyles$
|
|
4333
|
+
const useStyles$U = makeStyles({
|
|
4210
4334
|
rootDiv: {
|
|
4211
4335
|
flex: 1,
|
|
4212
4336
|
overflow: "hidden",
|
|
@@ -4281,6 +4405,37 @@ const useStyles$T = makeStyles({
|
|
|
4281
4405
|
function GetCommandDescription(command) {
|
|
4282
4406
|
return command.hotKey ? `${command.displayName} (${GetCommandHotKeyDescription(command)})` : command.displayName;
|
|
4283
4407
|
}
|
|
4408
|
+
const useTruncatingBody1Styles = makeStyles({
|
|
4409
|
+
container: {
|
|
4410
|
+
display: "block",
|
|
4411
|
+
overflow: "hidden",
|
|
4412
|
+
textOverflow: "ellipsis",
|
|
4413
|
+
whiteSpace: "nowrap",
|
|
4414
|
+
minWidth: 0,
|
|
4415
|
+
...typographyStyles.body1,
|
|
4416
|
+
},
|
|
4417
|
+
});
|
|
4418
|
+
const TruncatingBody1 = (props) => {
|
|
4419
|
+
const { text } = props;
|
|
4420
|
+
const classes = useTruncatingBody1Styles();
|
|
4421
|
+
const ref = useRef(null);
|
|
4422
|
+
const [isTruncated, setIsTruncated] = useState(false);
|
|
4423
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
4424
|
+
useEffect(() => {
|
|
4425
|
+
const element = ref.current;
|
|
4426
|
+
if (!element) {
|
|
4427
|
+
return undefined;
|
|
4428
|
+
}
|
|
4429
|
+
const update = () => {
|
|
4430
|
+
setIsTruncated(element.scrollWidth > element.clientWidth);
|
|
4431
|
+
};
|
|
4432
|
+
update();
|
|
4433
|
+
const observer = new ResizeObserver(update);
|
|
4434
|
+
observer.observe(element);
|
|
4435
|
+
return () => observer.disconnect();
|
|
4436
|
+
}, [text]);
|
|
4437
|
+
return (jsx(Tooltip$1, { content: text, positioning: "after", relationship: "description", visible: isTruncated && isHovered, onVisibleChange: (_, data) => setIsHovered(data.visible), children: jsx("span", { ref: ref, className: classes.container, children: text }) }));
|
|
4438
|
+
};
|
|
4284
4439
|
const ActionCommand = (props) => {
|
|
4285
4440
|
const { command } = props;
|
|
4286
4441
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
@@ -4292,7 +4447,7 @@ const ToggleCommand = (props) => {
|
|
|
4292
4447
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
4293
4448
|
const [Icon, isEnabled] = useObservableState(useCallback(() => [command.icon, command.isEnabled], [command]), command.onChange);
|
|
4294
4449
|
// TODO-iv2: Consolidate icon prop passing approach for inspector and shared components
|
|
4295
|
-
return (jsx(ToggleButton, { appearance: "transparent", title: GetCommandDescription(command), checkedIcon: Icon, value: isEnabled, onChange: (val) => (command.isEnabled = val) }));
|
|
4450
|
+
return (jsx(ToggleButton, { appearance: "transparent", title: GetCommandDescription(command), titlePositioning: "after", checkedIcon: Icon, value: isEnabled, onChange: (val) => (command.isEnabled = val) }));
|
|
4296
4451
|
};
|
|
4297
4452
|
// This "placeholder" command has a blank icon and is a no-op. It is used for aside
|
|
4298
4453
|
// alignment when some toggle commands are enabled. See more details on the commands
|
|
@@ -4315,14 +4470,14 @@ function MakeInlineCommandElement(command, isPlaceholder) {
|
|
|
4315
4470
|
}
|
|
4316
4471
|
const SceneTreeItem = (props) => {
|
|
4317
4472
|
const { isSelected, select } = props;
|
|
4318
|
-
const classes = useStyles$
|
|
4473
|
+
const classes = useStyles$U();
|
|
4319
4474
|
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
4320
4475
|
const treeItemLayoutClass = mergeClasses(classes.sceneTreeItemLayout, compactMode ? classes.treeItemLayoutCompact : undefined);
|
|
4321
4476
|
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"));
|
|
4322
4477
|
};
|
|
4323
4478
|
const SectionTreeItem = (props) => {
|
|
4324
4479
|
const { section, isFiltering, commandProviders, expandAll, collapseAll, isDropTarget, ...dropProps } = props;
|
|
4325
|
-
const classes = useStyles$
|
|
4480
|
+
const classes = useStyles$U();
|
|
4326
4481
|
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
4327
4482
|
// Get the commands that apply to this section.
|
|
4328
4483
|
const commands = useResource(useCallback(() => {
|
|
@@ -4339,7 +4494,7 @@ const SectionTreeItem = (props) => {
|
|
|
4339
4494
|
};
|
|
4340
4495
|
const EntityTreeItem = (props) => {
|
|
4341
4496
|
const { entityItem, isSelected, select, isFiltering, commandProviders, expandAll, collapseAll, isDragging, isDropTarget, ...dragProps } = props;
|
|
4342
|
-
const classes = useStyles$
|
|
4497
|
+
const classes = useStyles$U();
|
|
4343
4498
|
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
4344
4499
|
const hasChildren = !!entityItem.children?.length;
|
|
4345
4500
|
const displayInfo = useResource(useCallback(() => {
|
|
@@ -4452,10 +4607,10 @@ const EntityTreeItem = (props) => {
|
|
|
4452
4607
|
}, main: {
|
|
4453
4608
|
// Prevent the "main" content (the Body1 below) from growing too large and pushing the actions/aside out of view.
|
|
4454
4609
|
className: classes.treeItemLayoutMain,
|
|
4455
|
-
}, children: jsx(
|
|
4610
|
+
}, children: jsx(TruncatingBody1, { text: name }) }) }, GetEntityId$1(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] }) })] }));
|
|
4456
4611
|
};
|
|
4457
4612
|
const SceneExplorer = (props) => {
|
|
4458
|
-
const classes = useStyles$
|
|
4613
|
+
const classes = useStyles$U();
|
|
4459
4614
|
const { sections, entityCommandProviders, sectionCommandProviders, scene, selectedEntity = null } = props;
|
|
4460
4615
|
const [openItems, setOpenItems] = useState(new Set());
|
|
4461
4616
|
const [sceneVersion, setSceneVersion] = useState(0);
|
|
@@ -6081,7 +6236,7 @@ class CanvasGraphService {
|
|
|
6081
6236
|
}
|
|
6082
6237
|
}
|
|
6083
6238
|
|
|
6084
|
-
const useStyles$
|
|
6239
|
+
const useStyles$T = makeStyles({
|
|
6085
6240
|
canvas: {
|
|
6086
6241
|
flexGrow: 1,
|
|
6087
6242
|
width: "100%",
|
|
@@ -6090,7 +6245,7 @@ const useStyles$S = makeStyles({
|
|
|
6090
6245
|
});
|
|
6091
6246
|
const CanvasGraph = (props) => {
|
|
6092
6247
|
const { collector, scene, layoutObservable, returnToPlayheadObservable, onVisibleRangeChangedObservable, initialGraphSize } = props;
|
|
6093
|
-
const classes = useStyles$
|
|
6248
|
+
const classes = useStyles$T();
|
|
6094
6249
|
const canvasRef = useRef(null);
|
|
6095
6250
|
useEffect(() => {
|
|
6096
6251
|
if (!canvasRef.current) {
|
|
@@ -6179,7 +6334,7 @@ function EvaluateExpression(rawValue) {
|
|
|
6179
6334
|
return NaN;
|
|
6180
6335
|
}
|
|
6181
6336
|
}
|
|
6182
|
-
const useStyles$
|
|
6337
|
+
const useStyles$S = makeStyles({
|
|
6183
6338
|
icon: {
|
|
6184
6339
|
"&:hover": {
|
|
6185
6340
|
color: tokens.colorBrandForeground1,
|
|
@@ -6193,7 +6348,7 @@ const useStyles$R = makeStyles({
|
|
|
6193
6348
|
const SpinButton = forwardRef((props, ref) => {
|
|
6194
6349
|
SpinButton.displayName = "SpinButton2";
|
|
6195
6350
|
const inputClasses = useInputStyles$1();
|
|
6196
|
-
const classes = useStyles$
|
|
6351
|
+
const classes = useStyles$S();
|
|
6197
6352
|
const { size } = useContext(ToolContext);
|
|
6198
6353
|
const { min, max } = props;
|
|
6199
6354
|
const baseStep = props.step ?? 1;
|
|
@@ -6460,7 +6615,7 @@ const Dropdown = (props) => {
|
|
|
6460
6615
|
const NumberDropdown = Dropdown;
|
|
6461
6616
|
const StringDropdown = Dropdown;
|
|
6462
6617
|
|
|
6463
|
-
const useStyles$
|
|
6618
|
+
const useStyles$R = makeStyles({
|
|
6464
6619
|
surface: {
|
|
6465
6620
|
maxWidth: "400px",
|
|
6466
6621
|
},
|
|
@@ -6475,7 +6630,7 @@ const useStyles$Q = makeStyles({
|
|
|
6475
6630
|
const Popover = forwardRef((props, ref) => {
|
|
6476
6631
|
const { children, open: controlledOpen, onOpenChange, positioning, surfaceClassName } = props;
|
|
6477
6632
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
6478
|
-
const classes = useStyles$
|
|
6633
|
+
const classes = useStyles$R();
|
|
6479
6634
|
const isControlled = controlledOpen !== undefined;
|
|
6480
6635
|
const popoverOpen = isControlled ? controlledOpen : internalOpen;
|
|
6481
6636
|
const handleOpenChange = (_, data) => {
|
|
@@ -6719,7 +6874,7 @@ const InputAlphaField = (props) => {
|
|
|
6719
6874
|
} }));
|
|
6720
6875
|
};
|
|
6721
6876
|
|
|
6722
|
-
const useStyles$
|
|
6877
|
+
const useStyles$Q = makeStyles({
|
|
6723
6878
|
sidebar: {
|
|
6724
6879
|
display: "flex",
|
|
6725
6880
|
flexDirection: "column",
|
|
@@ -6783,7 +6938,7 @@ const useStyles$P = makeStyles({
|
|
|
6783
6938
|
});
|
|
6784
6939
|
const PerformanceSidebar = (props) => {
|
|
6785
6940
|
const { collector, onVisibleRangeChangedObservable } = props;
|
|
6786
|
-
const classes = useStyles$
|
|
6941
|
+
const classes = useStyles$Q();
|
|
6787
6942
|
// Map from id to IPerfMetadata information
|
|
6788
6943
|
const [metadataMap, setMetadataMap] = useState();
|
|
6789
6944
|
// Map from category to all the ids belonging to that category
|
|
@@ -6856,7 +7011,7 @@ const PerformanceSidebar = (props) => {
|
|
|
6856
7011
|
})] }, `category-${category || "version"}`))) }));
|
|
6857
7012
|
};
|
|
6858
7013
|
|
|
6859
|
-
const useStyles$
|
|
7014
|
+
const useStyles$P = makeStyles({
|
|
6860
7015
|
container: {
|
|
6861
7016
|
display: "flex",
|
|
6862
7017
|
flexDirection: "row",
|
|
@@ -6885,7 +7040,7 @@ const useStyles$O = makeStyles({
|
|
|
6885
7040
|
});
|
|
6886
7041
|
const PerformanceViewer = (props) => {
|
|
6887
7042
|
const { scene, layoutObservable, returnToLiveObservable, performanceCollector, initialGraphSize } = props;
|
|
6888
|
-
const classes = useStyles$
|
|
7043
|
+
const classes = useStyles$P();
|
|
6889
7044
|
const [onVisibleRangeChangedObservable] = useState(() => new Observable());
|
|
6890
7045
|
const onReturnToPlayheadClick = () => {
|
|
6891
7046
|
returnToLiveObservable.notifyObservers();
|
|
@@ -7052,14 +7207,14 @@ const TextPropertyLine = (props) => {
|
|
|
7052
7207
|
return (jsx(PropertyLine, { ...props, children: jsx(Body1, { title: title, children: value ?? "" }) }));
|
|
7053
7208
|
};
|
|
7054
7209
|
|
|
7055
|
-
const useStyles$
|
|
7210
|
+
const useStyles$O = makeStyles({
|
|
7056
7211
|
pinnedStatsPane: {
|
|
7057
7212
|
flex: "0 1 auto",
|
|
7058
7213
|
paddingBottom: tokens.spacingHorizontalM,
|
|
7059
7214
|
},
|
|
7060
7215
|
});
|
|
7061
7216
|
const StatsPane = (props) => {
|
|
7062
|
-
const classes = useStyles$
|
|
7217
|
+
const classes = useStyles$O();
|
|
7063
7218
|
const scene = props.context;
|
|
7064
7219
|
const engine = scene.getEngine();
|
|
7065
7220
|
const pollingObservable = usePollingObservable(250);
|
|
@@ -7222,7 +7377,7 @@ const ToolsServiceDefinition = {
|
|
|
7222
7377
|
*/
|
|
7223
7378
|
const ReactContextServiceIdentity = Symbol("ReactContextService");
|
|
7224
7379
|
|
|
7225
|
-
const useStyles$
|
|
7380
|
+
const useStyles$N = makeStyles({
|
|
7226
7381
|
dropdown: {
|
|
7227
7382
|
...UniformWidthStyling,
|
|
7228
7383
|
},
|
|
@@ -7234,7 +7389,7 @@ const useStyles$M = makeStyles({
|
|
|
7234
7389
|
*/
|
|
7235
7390
|
const DropdownPropertyLine = forwardRef((props, ref) => {
|
|
7236
7391
|
DropdownPropertyLine.displayName = "DropdownPropertyLine";
|
|
7237
|
-
const classes = useStyles$
|
|
7392
|
+
const classes = useStyles$N();
|
|
7238
7393
|
return (jsx(PropertyLine, { ...props, ref: ref, children: jsx(Dropdown, { ...props, className: classes.dropdown }) }));
|
|
7239
7394
|
});
|
|
7240
7395
|
/**
|
|
@@ -7392,7 +7547,7 @@ const SyncedSliderInput = (props) => {
|
|
|
7392
7547
|
return (jsxs("div", { className: mergeClasses(classes.container, props.className), 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: useCompactSizing ? classes.compactSpinButton : classes.spinButton, inputClassName: useCompactSizing ? classes.compactSpinButtonInput : classes.spinButtonInput, value: value, onChange: handleInputChange, step: props.step, disabled: props.disabled, disableDragButton: true })] })] }));
|
|
7393
7548
|
};
|
|
7394
7549
|
|
|
7395
|
-
const useStyles$
|
|
7550
|
+
const useStyles$M = makeStyles({
|
|
7396
7551
|
uniformWidth: {
|
|
7397
7552
|
...UniformWidthStyling,
|
|
7398
7553
|
},
|
|
@@ -7404,7 +7559,7 @@ const useStyles$L = makeStyles({
|
|
|
7404
7559
|
*/
|
|
7405
7560
|
const SyncedSliderPropertyLine = forwardRef((props, ref) => {
|
|
7406
7561
|
SyncedSliderPropertyLine.displayName = "SyncedSliderPropertyLine";
|
|
7407
|
-
const classes = useStyles$
|
|
7562
|
+
const classes = useStyles$M();
|
|
7408
7563
|
const { label, description, ...sliderProps } = props;
|
|
7409
7564
|
return (jsx(PropertyLine, { ref: ref, ...props, children: jsx(SyncedSliderInput, { ...sliderProps, className: mergeClasses(classes.uniformWidth, props.className) }) }));
|
|
7410
7565
|
});
|
|
@@ -7647,6 +7802,48 @@ const GizmoServiceDefinition = {
|
|
|
7647
7802
|
const getCameraGizmo = (camera) => getGizmo(camera, camera.getScene(), CameraGizmo, cameraGizmos, (camera, gizmo) => (gizmo.camera = camera));
|
|
7648
7803
|
const lightGizmos = new WeakMap();
|
|
7649
7804
|
const getLightGizmo = (light) => getGizmo(light, light.getScene(), LightGizmo, lightGizmos, (light, gizmo) => (gizmo.light = light));
|
|
7805
|
+
// Ref-counted spatial audio gizmos. Sound sources are not Babylon Nodes, so we can't reuse the helper above directly.
|
|
7806
|
+
// Unlike `getGizmo`, this doesn't override `gizmo.dispose` — it routes shared cleanup through a lambda
|
|
7807
|
+
// (avoiding both Function.bind and Function.call, which are prohibited by the repo's performance/style rules).
|
|
7808
|
+
const spatialAudioGizmos = new WeakMap();
|
|
7809
|
+
const getSpatialAudioGizmo = (soundSource, scene) => {
|
|
7810
|
+
let refCounted = spatialAudioGizmos.get(soundSource);
|
|
7811
|
+
if (!refCounted) {
|
|
7812
|
+
const utilityLayerRef = getUtilityLayer(scene);
|
|
7813
|
+
const gizmo = new SpatialAudioGizmo(utilityLayerRef.value);
|
|
7814
|
+
gizmo.soundSource = soundSource;
|
|
7815
|
+
let isCleanedUp = false;
|
|
7816
|
+
const cleanup = () => {
|
|
7817
|
+
if (isCleanedUp) {
|
|
7818
|
+
return;
|
|
7819
|
+
}
|
|
7820
|
+
isCleanedUp = true;
|
|
7821
|
+
sourceDisposedObserver.remove();
|
|
7822
|
+
gizmo.dispose();
|
|
7823
|
+
utilityLayerRef.dispose();
|
|
7824
|
+
spatialAudioGizmos.delete(soundSource);
|
|
7825
|
+
};
|
|
7826
|
+
// If the underlying sound source is disposed externally, tear the gizmo down too.
|
|
7827
|
+
const sourceDisposedObserver = soundSource.onDisposeObservable.addOnce(cleanup);
|
|
7828
|
+
refCounted = { gizmo, cleanup, refCount: 0 };
|
|
7829
|
+
spatialAudioGizmos.set(soundSource, refCounted);
|
|
7830
|
+
}
|
|
7831
|
+
refCounted.refCount++;
|
|
7832
|
+
const refCountedCapture = refCounted;
|
|
7833
|
+
let disposed = false;
|
|
7834
|
+
return {
|
|
7835
|
+
value: refCounted.gizmo,
|
|
7836
|
+
dispose: () => {
|
|
7837
|
+
if (!disposed) {
|
|
7838
|
+
disposed = true;
|
|
7839
|
+
refCountedCapture.refCount--;
|
|
7840
|
+
if (refCountedCapture.refCount === 0) {
|
|
7841
|
+
refCountedCapture.cleanup();
|
|
7842
|
+
}
|
|
7843
|
+
}
|
|
7844
|
+
},
|
|
7845
|
+
};
|
|
7846
|
+
};
|
|
7650
7847
|
// Gizmo mode/coordinates state and GizmoManager lifecycle.
|
|
7651
7848
|
let gizmoModeState = undefined;
|
|
7652
7849
|
const gizmoModeObservable = new Observable();
|
|
@@ -7782,6 +7979,7 @@ const GizmoServiceDefinition = {
|
|
|
7782
7979
|
getUtilityLayer,
|
|
7783
7980
|
getCameraGizmo,
|
|
7784
7981
|
getLightGizmo,
|
|
7982
|
+
getSpatialAudioGizmo,
|
|
7785
7983
|
getCameraGizmos: (scene) => scene.cameras.map((camera) => cameraGizmos.get(camera)?.gizmo).filter(Boolean),
|
|
7786
7984
|
getLightGizmos: (scene) => scene.lights.map((light) => lightGizmos.get(light)?.gizmo).filter(Boolean),
|
|
7787
7985
|
get gizmoMode() {
|
|
@@ -8354,17 +8552,24 @@ class ServiceContainer {
|
|
|
8354
8552
|
}
|
|
8355
8553
|
}
|
|
8356
8554
|
|
|
8555
|
+
/**
|
|
8556
|
+
* The unique identity symbol for the dialog service.
|
|
8557
|
+
*/
|
|
8558
|
+
const DialogServiceIdentity = Symbol("DialogService");
|
|
8559
|
+
|
|
8357
8560
|
/**
|
|
8358
8561
|
* The unique identity symbol for the toast service.
|
|
8359
8562
|
*/
|
|
8360
8563
|
const ToastServiceIdentity = Symbol("ToastService");
|
|
8361
8564
|
|
|
8565
|
+
const DialogContext = createContext({ showDialog: (options) => alert(options.title) });
|
|
8566
|
+
|
|
8362
8567
|
const ExtensionManagerContext = createContext(undefined);
|
|
8363
8568
|
function useExtensionManager() {
|
|
8364
8569
|
return useContext(ExtensionManagerContext)?.extensionManager;
|
|
8365
8570
|
}
|
|
8366
8571
|
|
|
8367
|
-
const useStyles$
|
|
8572
|
+
const useStyles$L = makeStyles({
|
|
8368
8573
|
themeButton: {
|
|
8369
8574
|
margin: 0,
|
|
8370
8575
|
},
|
|
@@ -8383,7 +8588,7 @@ const ThemeSelectorServiceDefinition = {
|
|
|
8383
8588
|
teachingMoment: false,
|
|
8384
8589
|
order: -300,
|
|
8385
8590
|
component: () => {
|
|
8386
|
-
const classes = useStyles$
|
|
8591
|
+
const classes = useStyles$L();
|
|
8387
8592
|
const { isDarkMode, themeMode, setThemeMode } = useThemeMode();
|
|
8388
8593
|
const onSelectedThemeChange = useCallback((e, data) => {
|
|
8389
8594
|
setThemeMode(data.checkedItems.includes("System") ? "system" : data.checkedItems[0].toLocaleLowerCase());
|
|
@@ -8400,7 +8605,7 @@ const ThemeSelectorServiceDefinition = {
|
|
|
8400
8605
|
},
|
|
8401
8606
|
};
|
|
8402
8607
|
|
|
8403
|
-
const useStyles$
|
|
8608
|
+
const useStyles$K = makeStyles({
|
|
8404
8609
|
app: {
|
|
8405
8610
|
colorScheme: "light dark",
|
|
8406
8611
|
flexGrow: 1,
|
|
@@ -8425,6 +8630,24 @@ const useStyles$J = makeStyles({
|
|
|
8425
8630
|
extensionErrorIcon: {
|
|
8426
8631
|
color: tokens.colorPaletteRedForeground1,
|
|
8427
8632
|
},
|
|
8633
|
+
dialogTitle: {
|
|
8634
|
+
display: "flex",
|
|
8635
|
+
flexDirection: "row",
|
|
8636
|
+
alignItems: "center",
|
|
8637
|
+
gap: tokens.spacingHorizontalS,
|
|
8638
|
+
},
|
|
8639
|
+
dialogIconSuccess: {
|
|
8640
|
+
color: tokens.colorStatusSuccessForeground1,
|
|
8641
|
+
},
|
|
8642
|
+
dialogIconError: {
|
|
8643
|
+
color: tokens.colorStatusDangerForeground1,
|
|
8644
|
+
},
|
|
8645
|
+
dialogIconWarning: {
|
|
8646
|
+
color: tokens.colorStatusWarningForeground1,
|
|
8647
|
+
},
|
|
8648
|
+
dialogIconInfo: {
|
|
8649
|
+
color: tokens.colorBrandForeground1,
|
|
8650
|
+
},
|
|
8428
8651
|
});
|
|
8429
8652
|
const ReactContextsWrapper = ({ contexts, children }) => {
|
|
8430
8653
|
return jsx(Fragment, { children: contexts.reduceRight((acc, entry) => createElement(entry.provider, { value: entry.value }, acc), children) });
|
|
@@ -8445,7 +8668,7 @@ function MakeModularTool(options) {
|
|
|
8445
8668
|
// This deferred resolves once the React effect cleanup (which disposes the ServiceContainer) is complete.
|
|
8446
8669
|
const disposeDeferred = new Deferred();
|
|
8447
8670
|
const modularToolRootComponent = () => {
|
|
8448
|
-
const classes = useStyles$
|
|
8671
|
+
const classes = useStyles$K();
|
|
8449
8672
|
const [extensionManagerContext, setExtensionManagerContext] = useState();
|
|
8450
8673
|
const [requiredExtensions, setRequiredExtensions] = useState();
|
|
8451
8674
|
const [requiredExtensionsDeferred, setRequiredExtensionsDeferred] = useState();
|
|
@@ -8460,6 +8683,21 @@ function MakeModularTool(options) {
|
|
|
8460
8683
|
setToastQueue([]);
|
|
8461
8684
|
}
|
|
8462
8685
|
}, [toastHandle, toastQueue]);
|
|
8686
|
+
// Queue of dialogs to display. We show one at a time (the one at the head of the queue).
|
|
8687
|
+
const [dialogQueue, dispatchDialogQueue] = useReducer((state, action) => {
|
|
8688
|
+
switch (action.type) {
|
|
8689
|
+
case "enqueue":
|
|
8690
|
+
return [...state, action.options];
|
|
8691
|
+
case "dequeue":
|
|
8692
|
+
return state.slice(1);
|
|
8693
|
+
}
|
|
8694
|
+
}, []);
|
|
8695
|
+
const showDialog = useCallback((dialogOptions) => {
|
|
8696
|
+
dispatchDialogQueue({ type: "enqueue", options: dialogOptions });
|
|
8697
|
+
}, []);
|
|
8698
|
+
const onDismissDialog = useCallback(() => {
|
|
8699
|
+
dispatchDialogQueue({ type: "dequeue" });
|
|
8700
|
+
}, []);
|
|
8463
8701
|
const [rootComponentService, setRootComponentService] = useState();
|
|
8464
8702
|
const [contexts, updateContexts] = useReducer((state, action) => {
|
|
8465
8703
|
switch (action.type) {
|
|
@@ -8510,6 +8748,12 @@ function MakeModularTool(options) {
|
|
|
8510
8748
|
},
|
|
8511
8749
|
}),
|
|
8512
8750
|
});
|
|
8751
|
+
// Expose the dialog service so non-React code (e.g. Observable callbacks) can show dialogs.
|
|
8752
|
+
serviceContainer.addService({
|
|
8753
|
+
friendlyName: "Dialog Service",
|
|
8754
|
+
produces: [DialogServiceIdentity],
|
|
8755
|
+
factory: () => ({ showDialog }),
|
|
8756
|
+
});
|
|
8513
8757
|
// Register the shell service (top level toolbar/side pane UI layout).
|
|
8514
8758
|
serviceContainer.addService(MakeShellServiceDefinition(options));
|
|
8515
8759
|
// Register a service that simply consumes the services we need before first render.
|
|
@@ -8532,7 +8776,7 @@ function MakeModularTool(options) {
|
|
|
8532
8776
|
}
|
|
8533
8777
|
// Register the extension list service (for browsing/installing extensions) if extension feeds are provided.
|
|
8534
8778
|
if (extensionFeeds.length > 0) {
|
|
8535
|
-
const { ExtensionListServiceDefinition } = await import('./extensionsListService-
|
|
8779
|
+
const { ExtensionListServiceDefinition } = await import('./extensionsListService-j6viqje8.js');
|
|
8536
8780
|
serviceContainer.addService(ExtensionListServiceDefinition);
|
|
8537
8781
|
}
|
|
8538
8782
|
// Register all external services (that make up a unique tool).
|
|
@@ -8599,16 +8843,36 @@ function MakeModularTool(options) {
|
|
|
8599
8843
|
const onAcknowledgedExtensionInstallError = useCallback(() => {
|
|
8600
8844
|
setExtensionInstallError(undefined);
|
|
8601
8845
|
}, [setExtensionInstallError]);
|
|
8846
|
+
// The dialog at the head of the queue, if any, is the one currently being displayed.
|
|
8847
|
+
const currentDialog = dialogQueue[0];
|
|
8848
|
+
const currentDialogIcon = (() => {
|
|
8849
|
+
switch (currentDialog?.intent) {
|
|
8850
|
+
case "success":
|
|
8851
|
+
return jsx(CheckmarkCircleRegular, { className: classes.dialogIconSuccess });
|
|
8852
|
+
case "error":
|
|
8853
|
+
return jsx(ErrorCircleRegular, { className: classes.dialogIconError });
|
|
8854
|
+
case "warning":
|
|
8855
|
+
return jsx(WarningRegular, { className: classes.dialogIconWarning });
|
|
8856
|
+
case "info":
|
|
8857
|
+
case undefined:
|
|
8858
|
+
return jsx(InfoRegular, { className: classes.dialogIconInfo });
|
|
8859
|
+
}
|
|
8860
|
+
})();
|
|
8602
8861
|
// Show a spinner until a main view has been set.
|
|
8603
8862
|
if (!rootComponentService) {
|
|
8604
|
-
return (jsx(ReactContextsWrapper, { contexts: contexts, children: jsx(SettingsStoreContext.Provider, { value: settingsStore, children: jsx(Theme, { className: classes.app, children: jsx(Spinner, { className: classes.spinner }) }) }) }));
|
|
8863
|
+
return (jsx(ReactContextsWrapper, { contexts: contexts, children: jsx(SettingsStoreContext.Provider, { value: settingsStore, children: jsx(Theme, { className: classes.app, targetDocument: targetDocument, children: jsx(Spinner, { className: classes.spinner }) }) }) }));
|
|
8605
8864
|
}
|
|
8606
8865
|
else {
|
|
8607
8866
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8608
8867
|
const Content = rootComponentService.rootComponent;
|
|
8609
|
-
return (jsx(ReactContextsWrapper, { contexts: contexts, children: jsx(SettingsStoreContext.Provider, { value: settingsStore, children: jsx(ExtensionManagerContext.Provider, { value: extensionManagerContext, children: jsx(Theme, { className: classes.app, children: jsxs(ToastProvider, { imperativeRef: setToastHandle, children: [jsx(Dialog$1, { 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$1, { 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, {}) })] }) }) }) }) }));
|
|
8868
|
+
return (jsx(ReactContextsWrapper, { contexts: contexts, children: jsx(SettingsStoreContext.Provider, { value: settingsStore, children: jsx(ExtensionManagerContext.Provider, { value: extensionManagerContext, children: jsx(Theme, { className: classes.app, targetDocument: targetDocument, children: jsxs(ToastProvider, { imperativeRef: setToastHandle, children: [jsx(Dialog$1, { 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$1, { 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(Dialog$1, { open: !!currentDialog, modalType: "alert", children: jsx(DialogSurface, { children: jsxs(DialogBody, { children: [jsx(DialogTitle, { children: jsxs("div", { className: classes.dialogTitle, children: [currentDialogIcon, currentDialog?.title] }) }), currentDialog?.content && jsx(DialogContent, { children: currentDialog.content }), jsx(DialogActions, { children: jsx(Button$1, { appearance: "primary", onClick: onDismissDialog, children: "OK" }) })] }) }) }), jsx(Suspense, { fallback: jsx(Spinner, { className: classes.spinner }), children: jsx(DialogContext.Provider, { value: { showDialog }, children: jsx(Content, {}) }) })] }) }) }) }) }));
|
|
8610
8869
|
}
|
|
8611
8870
|
};
|
|
8871
|
+
// Derive the target document from the container element. When the container is in a popup
|
|
8872
|
+
// window (or other document distinct from the main one), this is what makes Fluent inject
|
|
8873
|
+
// styles and render portals into the correct document.
|
|
8874
|
+
const containerOwnerDocument = containerElement.ownerDocument;
|
|
8875
|
+
const targetDocument = containerOwnerDocument && containerOwnerDocument !== document ? containerOwnerDocument : undefined;
|
|
8612
8876
|
// Set the container element to be a flex container so that the tool can be displayed properly.
|
|
8613
8877
|
const originalContainerElementDisplay = containerElement.style.display;
|
|
8614
8878
|
containerElement.style.display = "flex";
|
|
@@ -8653,14 +8917,14 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
8653
8917
|
description: "Adds a new panel for easy creation of various Babylon assets. This is a WIP extension...expect changes!",
|
|
8654
8918
|
keywords: ["creation", "tools"],
|
|
8655
8919
|
...BabylonWebResources,
|
|
8656
|
-
getExtensionModuleAsync: async () => await import('./quickCreateToolsService-
|
|
8920
|
+
getExtensionModuleAsync: async () => await import('./quickCreateToolsService-eZ4MCuJ2.js'),
|
|
8657
8921
|
},
|
|
8658
8922
|
{
|
|
8659
8923
|
name: "Reflector",
|
|
8660
8924
|
description: "Connects to the Reflector Bridge for real-time scene synchronization with the Babylon.js Sandbox.",
|
|
8661
8925
|
keywords: ["reflector", "bridge", "sync", "sandbox", "tools"],
|
|
8662
8926
|
...BabylonWebResources,
|
|
8663
|
-
getExtensionModuleAsync: async () => await import('./reflectorService-
|
|
8927
|
+
getExtensionModuleAsync: async () => await import('./reflectorService-2dP-GJrK.js'),
|
|
8664
8928
|
},
|
|
8665
8929
|
]);
|
|
8666
8930
|
|
|
@@ -9701,7 +9965,7 @@ const ColorSliders = ({ color, onSliderChange }) => (jsxs(Fragment, { children:
|
|
|
9701
9965
|
const Color3PropertyLine = ColorPropertyLine;
|
|
9702
9966
|
const Color4PropertyLine = ColorPropertyLine;
|
|
9703
9967
|
|
|
9704
|
-
const useStyles$
|
|
9968
|
+
const useStyles$J = makeStyles({
|
|
9705
9969
|
uniformWidth: {
|
|
9706
9970
|
...UniformWidthStyling,
|
|
9707
9971
|
},
|
|
@@ -9713,7 +9977,7 @@ const useStyles$I = makeStyles({
|
|
|
9713
9977
|
*/
|
|
9714
9978
|
const TextInputPropertyLine = (props) => {
|
|
9715
9979
|
TextInputPropertyLine.displayName = "TextInputPropertyLine";
|
|
9716
|
-
const classes = useStyles$
|
|
9980
|
+
const classes = useStyles$J();
|
|
9717
9981
|
return (jsx(PropertyLine, { ...props, children: jsx(TextInput, { ...props, className: mergeClasses(classes.uniformWidth, props.className) }) }));
|
|
9718
9982
|
};
|
|
9719
9983
|
/**
|
|
@@ -9724,7 +9988,7 @@ const TextInputPropertyLine = (props) => {
|
|
|
9724
9988
|
*/
|
|
9725
9989
|
const NumberInputPropertyLine = (props) => {
|
|
9726
9990
|
NumberInputPropertyLine.displayName = "NumberInputPropertyLine";
|
|
9727
|
-
const classes = useStyles$
|
|
9991
|
+
const classes = useStyles$J();
|
|
9728
9992
|
return (jsx(PropertyLine, { ...props, children: jsx(SpinButton, { ...props, className: mergeClasses(classes.uniformWidth, props.className) }) }));
|
|
9729
9993
|
};
|
|
9730
9994
|
|
|
@@ -9856,7 +10120,7 @@ const LegacyInspectableObjectPropertiesServiceDefinition = {
|
|
|
9856
10120
|
};
|
|
9857
10121
|
|
|
9858
10122
|
const DocUrl = "https://www.npmjs.com/package/@babylonjs/inspector#inspector-cli";
|
|
9859
|
-
const useStyles$
|
|
10123
|
+
const useStyles$I = makeStyles({
|
|
9860
10124
|
tooltipContent: {
|
|
9861
10125
|
display: "flex",
|
|
9862
10126
|
flexDirection: "column",
|
|
@@ -9874,7 +10138,7 @@ const CliConnectionStatusServiceDefinition = {
|
|
|
9874
10138
|
teachingMoment: false,
|
|
9875
10139
|
order: 0 /* DefaultToolbarItemOrder.CliStatus */,
|
|
9876
10140
|
component: () => {
|
|
9877
|
-
const classes = useStyles$
|
|
10141
|
+
const classes = useStyles$I();
|
|
9878
10142
|
const isEnabled = useObservableState(() => cliConnectionStatus.isEnabled, cliConnectionStatus.onConnectionStatusChanged);
|
|
9879
10143
|
const isConnected = useObservableState(() => cliConnectionStatus.isConnected, cliConnectionStatus.onConnectionStatusChanged);
|
|
9880
10144
|
const { showToast } = useToast();
|
|
@@ -9935,7 +10199,7 @@ const BreakTangentIcon = createFluentIcon("BreakTangent", "20", '<g transform="s
|
|
|
9935
10199
|
const UnifyTangentIcon = createFluentIcon("UnifyTangent", "20", '<g transform="scale(0.5)"><path d="M27.94,18.28a1.49,1.49,0,0,0-1.41,1h-5l-1.62-1.63-1.62,1.63h-5a1.5,1.5,0,1,0,0,1h5l1.62,1.62,1.62-1.62h5a1.5,1.5,0,1,0,1.41-2Z"/></g>');
|
|
9936
10200
|
const StepTangentIcon = createFluentIcon("StepTangent", "20", '<g transform="scale(0.5)"><path d="M29,16.71a1.5,1.5,0,1,0-2,1.41v5.67H11v1H28V18.12A1.51,1.51,0,0,0,29,16.71Z"/></g>');
|
|
9937
10201
|
|
|
9938
|
-
const useStyles$
|
|
10202
|
+
const useStyles$H = makeStyles({
|
|
9939
10203
|
coordinatesModeButton: {
|
|
9940
10204
|
margin: `0 0 0 ${tokens.spacingHorizontalXS}`,
|
|
9941
10205
|
},
|
|
@@ -9951,7 +10215,7 @@ const useStyles$G = makeStyles({
|
|
|
9951
10215
|
});
|
|
9952
10216
|
const GizmoToolbar = (props) => {
|
|
9953
10217
|
const { gizmoService, sceneContext } = props;
|
|
9954
|
-
const classes = useStyles$
|
|
10218
|
+
const classes = useStyles$H();
|
|
9955
10219
|
const gizmoMode = useObservableState(() => gizmoService.gizmoMode, gizmoService.onGizmoModeChanged);
|
|
9956
10220
|
const coordinatesMode = useObservableState(() => gizmoService.coordinatesMode, gizmoService.onCoordinatesModeChanged);
|
|
9957
10221
|
const cameraGizmo = useObservableState(() => gizmoService.gizmoCamera, gizmoService.onCameraGizmoChanged);
|
|
@@ -10080,7 +10344,7 @@ const HighlightServiceDefinition = {
|
|
|
10080
10344
|
},
|
|
10081
10345
|
};
|
|
10082
10346
|
|
|
10083
|
-
const useStyles$
|
|
10347
|
+
const useStyles$G = makeStyles({
|
|
10084
10348
|
badge: {
|
|
10085
10349
|
margin: tokens.spacingHorizontalXXS,
|
|
10086
10350
|
fontFamily: "monospace",
|
|
@@ -10097,7 +10361,7 @@ const MiniStatsServiceDefinition = {
|
|
|
10097
10361
|
order: 300 /* DefaultToolbarItemOrder.FrameRate */,
|
|
10098
10362
|
teachingMoment: false,
|
|
10099
10363
|
component: () => {
|
|
10100
|
-
const classes = useStyles$
|
|
10364
|
+
const classes = useStyles$G();
|
|
10101
10365
|
const scene = useObservableState(useCallback(() => sceneContext.currentScene, [sceneContext.currentScene]), sceneContext.currentSceneObservable);
|
|
10102
10366
|
const engine = scene?.getEngine();
|
|
10103
10367
|
const pollingObservable = usePollingObservable(250);
|
|
@@ -10426,7 +10690,7 @@ function useCurveEditor() {
|
|
|
10426
10690
|
return context;
|
|
10427
10691
|
}
|
|
10428
10692
|
|
|
10429
|
-
const useStyles$
|
|
10693
|
+
const useStyles$F = makeStyles({
|
|
10430
10694
|
root: {
|
|
10431
10695
|
display: "flex",
|
|
10432
10696
|
flexDirection: "row",
|
|
@@ -10470,7 +10734,7 @@ const useStyles$E = makeStyles({
|
|
|
10470
10734
|
* @returns The top bar component
|
|
10471
10735
|
*/
|
|
10472
10736
|
const TopBar = () => {
|
|
10473
|
-
const styles = useStyles$
|
|
10737
|
+
const styles = useStyles$F();
|
|
10474
10738
|
const { state, observables } = useCurveEditor();
|
|
10475
10739
|
const [keyFrameValue, setKeyFrameValue] = useState(null);
|
|
10476
10740
|
const [keyValue, setKeyValue] = useState(null);
|
|
@@ -10563,7 +10827,7 @@ const ColorChannelColors = {
|
|
|
10563
10827
|
*/
|
|
10564
10828
|
const DefaultCurveColor = "#ffffff";
|
|
10565
10829
|
|
|
10566
|
-
const useStyles$
|
|
10830
|
+
const useStyles$E = makeStyles({
|
|
10567
10831
|
root: {
|
|
10568
10832
|
display: "flex",
|
|
10569
10833
|
flexDirection: "column",
|
|
@@ -10605,7 +10869,7 @@ const LOOP_MODES$1 = [
|
|
|
10605
10869
|
* @returns The edit animation panel component
|
|
10606
10870
|
*/
|
|
10607
10871
|
const EditAnimationPanel = ({ animation, onClose }) => {
|
|
10608
|
-
const styles = useStyles$
|
|
10872
|
+
const styles = useStyles$E();
|
|
10609
10873
|
const { observables } = useCurveEditor();
|
|
10610
10874
|
const [name, setName] = useState(animation.name);
|
|
10611
10875
|
const [property, setProperty] = useState(animation.targetProperty);
|
|
@@ -10636,7 +10900,7 @@ const EditAnimationPanel = ({ animation, onClose }) => {
|
|
|
10636
10900
|
return (jsxs("div", { className: styles.root, children: [jsxs("div", { className: styles.form, children: [jsxs("div", { className: styles.row, children: [jsx(Label, { children: "Display Name" }), jsx(Input, { value: name, onChange: (_, data) => setName(data.value), placeholder: "Animation name" })] }), jsxs("div", { className: styles.row, children: [jsx(Label, { children: "Property" }), jsx(Input, { value: property, onChange: (_, data) => setProperty(data.value), placeholder: "e.g., position, rotation, scaling" })] }), jsxs("div", { className: styles.row, children: [jsx(Label, { children: "Loop Mode" }), jsx(Dropdown$1, { value: getLoopModeLabel(loopMode), selectedOptions: [loopMode.toString()], onOptionSelect: (_, data) => setLoopMode(Number(data.optionValue)), positioning: "below", inlinePopup: true, children: LOOP_MODES$1.map((mode) => (jsx(Option, { value: mode.value.toString(), children: mode.label }, mode.value))) })] })] }), jsxs("div", { className: styles.buttons, children: [jsx(Button, { appearance: "primary", onClick: saveChanges, label: "Save", disabled: !isValid }), jsx(Button, { appearance: "subtle", onClick: onClose, label: "Cancel" })] })] }));
|
|
10637
10901
|
};
|
|
10638
10902
|
|
|
10639
|
-
const useStyles$
|
|
10903
|
+
const useStyles$D = makeStyles({
|
|
10640
10904
|
root: {
|
|
10641
10905
|
display: "flex",
|
|
10642
10906
|
flexDirection: "column",
|
|
@@ -10702,7 +10966,7 @@ const useStyles$C = makeStyles({
|
|
|
10702
10966
|
* @returns Animation entry component
|
|
10703
10967
|
*/
|
|
10704
10968
|
const AnimationEntry = ({ animation }) => {
|
|
10705
|
-
const styles = useStyles$
|
|
10969
|
+
const styles = useStyles$D();
|
|
10706
10970
|
const { state, actions, observables } = useCurveEditor();
|
|
10707
10971
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
10708
10972
|
const [isHovered, setIsHovered] = useState(false);
|
|
@@ -10781,7 +11045,7 @@ const AnimationEntry = ({ animation }) => {
|
|
|
10781
11045
|
* @returns Animation sub-entry component
|
|
10782
11046
|
*/
|
|
10783
11047
|
const AnimationSubEntry = ({ animation, subName, color }) => {
|
|
10784
|
-
const styles = useStyles$
|
|
11048
|
+
const styles = useStyles$D();
|
|
10785
11049
|
const { actions, observables } = useCurveEditor();
|
|
10786
11050
|
const activeChannel = actions.getActiveChannel(animation);
|
|
10787
11051
|
const isThisChannelActive = activeChannel === color;
|
|
@@ -10804,7 +11068,7 @@ const AnimationSubEntry = ({ animation, subName, color }) => {
|
|
|
10804
11068
|
* @returns Animation list component
|
|
10805
11069
|
*/
|
|
10806
11070
|
const AnimationList = () => {
|
|
10807
|
-
const styles = useStyles$
|
|
11071
|
+
const styles = useStyles$D();
|
|
10808
11072
|
const { state, observables } = useCurveEditor();
|
|
10809
11073
|
// Re-render when animations are loaded or changed (e.g. animation deleted)
|
|
10810
11074
|
// useCallback stabilizes the accessor to prevent infinite re-render loops
|
|
@@ -10817,7 +11081,7 @@ const AnimationList = () => {
|
|
|
10817
11081
|
}) }));
|
|
10818
11082
|
};
|
|
10819
11083
|
|
|
10820
|
-
const useStyles$
|
|
11084
|
+
const useStyles$C = makeStyles({
|
|
10821
11085
|
root: {
|
|
10822
11086
|
display: "flex",
|
|
10823
11087
|
flexDirection: "column",
|
|
@@ -10866,7 +11130,7 @@ const LoopModeOptions = LOOP_MODES.map((lm) => ({ label: lm, value: lm }));
|
|
|
10866
11130
|
* @returns The add animation panel component
|
|
10867
11131
|
*/
|
|
10868
11132
|
const AddAnimationPanel = ({ onClose }) => {
|
|
10869
|
-
const styles = useStyles$
|
|
11133
|
+
const styles = useStyles$C();
|
|
10870
11134
|
const { state, actions, observables } = useCurveEditor();
|
|
10871
11135
|
const [name, setName] = useState("");
|
|
10872
11136
|
const [mode, setMode] = useState("List");
|
|
@@ -11083,7 +11347,7 @@ const AddAnimationPanel = ({ onClose }) => {
|
|
|
11083
11347
|
return (jsxs("div", { className: styles.root, children: [jsx("div", { className: styles.header, children: jsx("div", { className: styles.title, children: "Add Animation" }) }), jsxs("div", { className: styles.form, children: [jsxs("div", { className: styles.row, children: [jsx(Label, { children: "Display Name" }), jsx(TextInput, { value: name, onChange: setName })] }), jsx("div", { className: styles.row, children: jsx(StringDropdown, { value: mode, onChange: (val) => setMode(val), options: ModeOptions, disabled: properties.length === 0, infoLabel: { label: "Mode" } }) }), jsxs("div", { className: styles.row, children: [jsx(Label, { children: "Property" }), isCustomMode ? (jsx(TextInput, { value: customProperty, onChange: setCustomProperty })) : (jsx(StringDropdown, { value: selectedProperty, onChange: (val) => setSelectedProperty(val), options: properties.map((p) => ({ label: p, value: p })) }))] }), jsxs("div", { className: styles.row, children: [jsx(Label, { children: "Type" }), isCustomMode ? (jsx(StringDropdown, { value: animationType, onChange: (val) => setAnimationType(val), options: AnimationTypeOptions })) : (jsx("div", { className: styles.typeDisplay, children: inferredType }))] }), jsx("div", { className: styles.row, children: jsx(StringDropdown, { value: loopMode, onChange: (val) => setLoopMode(val), options: LoopModeOptions, infoLabel: { label: "Loop Mode" } }) })] }), jsxs("div", { className: styles.buttons, children: [jsx(Button, { appearance: "primary", onClick: createAnimation, disabled: !isValid, label: "Create" }), jsx(Button, { appearance: "subtle", onClick: onClose, label: "Cancel" })] })] }));
|
|
11084
11348
|
};
|
|
11085
11349
|
|
|
11086
|
-
const useStyles$
|
|
11350
|
+
const useStyles$B = makeStyles({
|
|
11087
11351
|
root: {
|
|
11088
11352
|
display: "flex",
|
|
11089
11353
|
flexDirection: "column",
|
|
@@ -11126,7 +11390,7 @@ const useStyles$A = makeStyles({
|
|
|
11126
11390
|
* @returns The load animation panel component
|
|
11127
11391
|
*/
|
|
11128
11392
|
const LoadAnimationPanel = ({ onClose }) => {
|
|
11129
|
-
const styles = useStyles$
|
|
11393
|
+
const styles = useStyles$B();
|
|
11130
11394
|
const { state, actions, observables } = useCurveEditor();
|
|
11131
11395
|
const [snippetIdInput, setSnippetIdInput] = useState("");
|
|
11132
11396
|
const [loadedSnippetId, setLoadedSnippetId] = useState(null);
|
|
@@ -11265,7 +11529,7 @@ class StringTools {
|
|
|
11265
11529
|
}
|
|
11266
11530
|
}
|
|
11267
11531
|
|
|
11268
|
-
const useStyles$
|
|
11532
|
+
const useStyles$A = makeStyles({
|
|
11269
11533
|
root: {
|
|
11270
11534
|
display: "flex",
|
|
11271
11535
|
flexDirection: "column",
|
|
@@ -11310,7 +11574,7 @@ const useStyles$z = makeStyles({
|
|
|
11310
11574
|
* @returns The save animation panel component
|
|
11311
11575
|
*/
|
|
11312
11576
|
const SaveAnimationPanel = ({ onClose: _onClose }) => {
|
|
11313
|
-
const styles = useStyles$
|
|
11577
|
+
const styles = useStyles$A();
|
|
11314
11578
|
const { state } = useCurveEditor();
|
|
11315
11579
|
const [selectedAnimations, setSelectedAnimations] = useState(() => {
|
|
11316
11580
|
if (!state.animations) {
|
|
@@ -11383,7 +11647,7 @@ const SaveAnimationPanel = ({ onClose: _onClose }) => {
|
|
|
11383
11647
|
}) }), jsxs("div", { className: styles.buttons, children: [jsx(Button, { appearance: "primary", onClick: saveToSnippetServer, disabled: selectedAnimations.length === 0 || isSaving, label: isSaving ? "Saving..." : "Save to Snippet Server" }), jsx(Button, { appearance: "secondary", onClick: saveToFile, disabled: selectedAnimations.length === 0, label: "Save to File" })] }), saveError && jsx("div", { className: styles.errorText, children: saveError }), snippetId && jsxs("div", { className: styles.snippetId, children: ["Saved! Snippet ID: ", snippetId] })] }));
|
|
11384
11648
|
};
|
|
11385
11649
|
|
|
11386
|
-
const useStyles$
|
|
11650
|
+
const useStyles$z = makeStyles({
|
|
11387
11651
|
root: {
|
|
11388
11652
|
display: "flex",
|
|
11389
11653
|
flexDirection: "column",
|
|
@@ -11437,7 +11701,7 @@ const useStyles$y = makeStyles({
|
|
|
11437
11701
|
* @returns The sidebar component
|
|
11438
11702
|
*/
|
|
11439
11703
|
const SideBar = () => {
|
|
11440
|
-
const styles = useStyles$
|
|
11704
|
+
const styles = useStyles$z();
|
|
11441
11705
|
const { state, actions, observables } = useCurveEditor();
|
|
11442
11706
|
const [openPopover, setOpenPopover] = useState(null);
|
|
11443
11707
|
const [fps, setFps] = useState(60);
|
|
@@ -12425,7 +12689,7 @@ const KeyPointComponent = (props) => {
|
|
|
12425
12689
|
} })] }))] }))] }));
|
|
12426
12690
|
};
|
|
12427
12691
|
|
|
12428
|
-
const useStyles$
|
|
12692
|
+
const useStyles$y = makeStyles({
|
|
12429
12693
|
root: {
|
|
12430
12694
|
position: "absolute",
|
|
12431
12695
|
top: 0,
|
|
@@ -12609,7 +12873,7 @@ function ExtractValuesFromKeys(keys, curves) {
|
|
|
12609
12873
|
* @returns The graph component
|
|
12610
12874
|
*/
|
|
12611
12875
|
const Graph = ({ width, height }) => {
|
|
12612
|
-
const styles = useStyles$
|
|
12876
|
+
const styles = useStyles$y();
|
|
12613
12877
|
const { state, actions, observables } = useCurveEditor();
|
|
12614
12878
|
const svgRef = useRef(null);
|
|
12615
12879
|
const [scale, setScale] = useState(1);
|
|
@@ -12972,7 +13236,7 @@ const Graph = ({ width, height }) => {
|
|
|
12972
13236
|
}), renderValueAxis()] })] }));
|
|
12973
13237
|
};
|
|
12974
13238
|
|
|
12975
|
-
const useStyles$
|
|
13239
|
+
const useStyles$x = makeStyles({
|
|
12976
13240
|
root: {
|
|
12977
13241
|
position: "absolute",
|
|
12978
13242
|
top: 0,
|
|
@@ -13015,7 +13279,7 @@ const useStyles$w = makeStyles({
|
|
|
13015
13279
|
* @returns The playhead component
|
|
13016
13280
|
*/
|
|
13017
13281
|
const PlayHead = ({ width, height: _height }) => {
|
|
13018
|
-
const styles = useStyles$
|
|
13282
|
+
const styles = useStyles$x();
|
|
13019
13283
|
const { state, actions, observables } = useCurveEditor();
|
|
13020
13284
|
const [isDragging, setIsDragging] = useState(false);
|
|
13021
13285
|
// Use refs for all mutable values to avoid render cycles
|
|
@@ -13166,7 +13430,7 @@ const PlayHead = ({ width, height: _height }) => {
|
|
|
13166
13430
|
return (jsxs("div", { className: styles.root, children: [jsx("div", { ref: lineRef, className: styles.line, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp }), jsx("div", { ref: handleRef, className: styles.handle, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp })] }));
|
|
13167
13431
|
};
|
|
13168
13432
|
|
|
13169
|
-
const useStyles$
|
|
13433
|
+
const useStyles$w = makeStyles({
|
|
13170
13434
|
root: {
|
|
13171
13435
|
display: "flex",
|
|
13172
13436
|
flexDirection: "row",
|
|
@@ -13198,7 +13462,7 @@ const useStyles$v = makeStyles({
|
|
|
13198
13462
|
* @returns The frame bar component
|
|
13199
13463
|
*/
|
|
13200
13464
|
const FrameBar = ({ width }) => {
|
|
13201
|
-
const styles = useStyles$
|
|
13465
|
+
const styles = useStyles$w();
|
|
13202
13466
|
const { state, observables } = useCurveEditor();
|
|
13203
13467
|
const containerRef = useRef(null);
|
|
13204
13468
|
const [scale, setScale] = useState(1);
|
|
@@ -13256,7 +13520,7 @@ const FrameBar = ({ width }) => {
|
|
|
13256
13520
|
return (jsx("div", { className: styles.root, ref: containerRef, children: renderTicks() }));
|
|
13257
13521
|
};
|
|
13258
13522
|
|
|
13259
|
-
const useStyles$
|
|
13523
|
+
const useStyles$v = makeStyles({
|
|
13260
13524
|
root: {
|
|
13261
13525
|
display: "flex",
|
|
13262
13526
|
flexDirection: "column",
|
|
@@ -13297,7 +13561,7 @@ const OFFSET_X = 10;
|
|
|
13297
13561
|
* @returns The range frame bar component
|
|
13298
13562
|
*/
|
|
13299
13563
|
const RangeFrameBar = ({ width }) => {
|
|
13300
|
-
const styles = useStyles$
|
|
13564
|
+
const styles = useStyles$v();
|
|
13301
13565
|
const { state, actions, observables } = useCurveEditor();
|
|
13302
13566
|
const svgRef = useRef(null);
|
|
13303
13567
|
const [viewWidth, setViewWidth] = useState(width);
|
|
@@ -13408,7 +13672,7 @@ const RangeFrameBar = ({ width }) => {
|
|
|
13408
13672
|
}), renderKeyframes, renderActiveFrame] }) }));
|
|
13409
13673
|
};
|
|
13410
13674
|
|
|
13411
|
-
const useStyles$
|
|
13675
|
+
const useStyles$u = makeStyles({
|
|
13412
13676
|
root: {
|
|
13413
13677
|
display: "flex",
|
|
13414
13678
|
flexDirection: "column",
|
|
@@ -13440,7 +13704,7 @@ const useStyles$t = makeStyles({
|
|
|
13440
13704
|
* @returns The canvas component
|
|
13441
13705
|
*/
|
|
13442
13706
|
const Canvas = () => {
|
|
13443
|
-
const styles = useStyles$
|
|
13707
|
+
const styles = useStyles$u();
|
|
13444
13708
|
const { observables } = useCurveEditor();
|
|
13445
13709
|
const containerRef = useRef(null);
|
|
13446
13710
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
|
@@ -13470,7 +13734,7 @@ const Canvas = () => {
|
|
|
13470
13734
|
return (jsxs("div", { className: styles.root, ref: containerRef, children: [jsx("div", { className: styles.frameBar, children: jsx(FrameBar, { width: dimensions.width }) }), jsxs("div", { className: styles.canvasArea, children: [jsx(Graph, { width: dimensions.width, height: dimensions.height - 70 }), jsx(PlayHead, { width: dimensions.width, height: dimensions.height - 70 })] }), jsx("div", { className: styles.rangeFrameBar, children: jsx(RangeFrameBar, { width: dimensions.width }) })] }));
|
|
13471
13735
|
};
|
|
13472
13736
|
|
|
13473
|
-
const useStyles$
|
|
13737
|
+
const useStyles$t = makeStyles({
|
|
13474
13738
|
root: {
|
|
13475
13739
|
flex: 1,
|
|
13476
13740
|
height: "25px",
|
|
@@ -13532,7 +13796,7 @@ const useStyles$s = makeStyles({
|
|
|
13532
13796
|
* @returns The range selector component
|
|
13533
13797
|
*/
|
|
13534
13798
|
const RangeSelector = () => {
|
|
13535
|
-
const styles = useStyles$
|
|
13799
|
+
const styles = useStyles$t();
|
|
13536
13800
|
const { state, actions, observables } = useCurveEditor();
|
|
13537
13801
|
const containerRef = useRef(null);
|
|
13538
13802
|
const scrollbarRef = useRef(null);
|
|
@@ -13677,7 +13941,7 @@ function GetKeyAtAnyFrameIndex(animations, frame) {
|
|
|
13677
13941
|
}
|
|
13678
13942
|
return false;
|
|
13679
13943
|
}
|
|
13680
|
-
const useStyles$
|
|
13944
|
+
const useStyles$s = makeStyles({
|
|
13681
13945
|
root: {
|
|
13682
13946
|
display: "flex",
|
|
13683
13947
|
flexDirection: "row",
|
|
@@ -13734,7 +13998,7 @@ MediaControls.displayName = "MediaControls";
|
|
|
13734
13998
|
* @returns The BottomBar component.
|
|
13735
13999
|
*/
|
|
13736
14000
|
const BottomBar = () => {
|
|
13737
|
-
const styles = useStyles$
|
|
14001
|
+
const styles = useStyles$s();
|
|
13738
14002
|
const { state, actions, observables } = useCurveEditor();
|
|
13739
14003
|
// Track display frame separately for smooth updates during playback
|
|
13740
14004
|
const [displayFrame, setDisplayFrame] = useState(state.activeFrame);
|
|
@@ -13849,7 +14113,7 @@ const BottomBar = () => {
|
|
|
13849
14113
|
return (jsxs("div", { className: styles.root, children: [jsx("div", { className: styles.mediaControls, children: jsx(MediaControls, { hasActiveAnimations: hasActiveAnimations, isPlaying: state.isPlaying, forwardAnimation: state.forwardAnimation, onPlayForward: handlePlayForward, onPlayBackward: handlePlayBackward, onStop: handleStop, onPrevKey: handlePrevKey, onNextKey: handleNextKey, onFirstFrame: handleFirstFrame, onLastFrame: handleLastFrame }) }), jsxs("div", { className: styles.frameDisplay, children: [jsx("div", { className: styles.frameLabel, children: "Frame:" }), jsx(SpinButton, { className: styles.spinButton, value: displayFrame, onChange: handleFrameChange, min: state.fromKey, max: state.toKey, disabled: !hasActiveAnimations })] }), jsx(RangeSelector, {}), jsxs("div", { className: styles.clipLengthSection, children: [jsx("div", { className: styles.frameLabel, children: "Clip Length:" }), jsx(SpinButton, { className: styles.spinButton, value: clipLength, onChange: handleClipLengthChange, min: 1, disabled: !hasActiveAnimations })] })] }));
|
|
13850
14114
|
};
|
|
13851
14115
|
|
|
13852
|
-
const useStyles$
|
|
14116
|
+
const useStyles$r = makeStyles({
|
|
13853
14117
|
root: {
|
|
13854
14118
|
display: "flex",
|
|
13855
14119
|
flexDirection: "column",
|
|
@@ -13898,7 +14162,7 @@ const useStyles$q = makeStyles({
|
|
|
13898
14162
|
* @returns The curve editor content
|
|
13899
14163
|
*/
|
|
13900
14164
|
const CurveEditorContent = () => {
|
|
13901
|
-
const styles = useStyles$
|
|
14165
|
+
const styles = useStyles$r();
|
|
13902
14166
|
const { state, actions, observables } = useCurveEditor();
|
|
13903
14167
|
const rootRef = useRef(null);
|
|
13904
14168
|
const prepareRef = useRef(() => actions.prepare());
|
|
@@ -14255,7 +14519,7 @@ const AtmospherePropertiesServiceDefinition = {
|
|
|
14255
14519
|
},
|
|
14256
14520
|
};
|
|
14257
14521
|
|
|
14258
|
-
function useSoundState(sound) {
|
|
14522
|
+
function useSoundState$1(sound) {
|
|
14259
14523
|
const stateChangedObservables = [
|
|
14260
14524
|
useInterceptObservable("function", sound, "play"),
|
|
14261
14525
|
useInterceptObservable("function", sound, "pause"),
|
|
@@ -14267,12 +14531,12 @@ function useSoundState(sound) {
|
|
|
14267
14531
|
}
|
|
14268
14532
|
const SoundGeneralProperties = (props) => {
|
|
14269
14533
|
const { sound } = props;
|
|
14270
|
-
const soundState = useSoundState(sound);
|
|
14534
|
+
const soundState = useSoundState$1(sound);
|
|
14271
14535
|
return (jsx(Fragment, { children: jsx(TextPropertyLine, { label: "Status", value: soundState }) }));
|
|
14272
14536
|
};
|
|
14273
14537
|
const SoundCommandProperties = (props) => {
|
|
14274
14538
|
const { sound } = props;
|
|
14275
|
-
const soundState = useSoundState(sound);
|
|
14539
|
+
const soundState = useSoundState$1(sound);
|
|
14276
14540
|
const volume = useObservableState(useCallback(() => sound.getVolume(), [sound]), useInterceptObservable("function", sound, "setVolume"));
|
|
14277
14541
|
return (jsxs(Fragment, { children: [jsx(ButtonLine, { uniqueId: "Start/Stop", label: soundState === "Playing" ? "Pause" : "Play", icon: soundState === "Playing" ? PauseRegular : PlayRegular, onClick: () => {
|
|
14278
14542
|
if (soundState === "Playing") {
|
|
@@ -14286,11 +14550,196 @@ const SoundCommandProperties = (props) => {
|
|
|
14286
14550
|
} }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Loop", target: sound, propertyKey: "loop" })] }));
|
|
14287
14551
|
};
|
|
14288
14552
|
|
|
14553
|
+
/**
|
|
14554
|
+
* Spatial-audio property line that shows the scene node a v2 sound or sound source is attached to,
|
|
14555
|
+
* with a clickable link to navigate to that node in the inspector.
|
|
14556
|
+
* @returns The rendered property line.
|
|
14557
|
+
*/
|
|
14558
|
+
const AudioV2SpatialAttachmentProperties = ({ source, selectionService }) => {
|
|
14559
|
+
// Intercept attach/detach on this instance's spatial sub-property so the link refreshes when attachment changes.
|
|
14560
|
+
const onAttach = useInterceptObservable("function", source.spatial, "attach");
|
|
14561
|
+
const onDetach = useInterceptObservable("function", source.spatial, "detach");
|
|
14562
|
+
const attachedNode = useObservableState(() => source.spatial.attachedNode, onAttach, onDetach);
|
|
14563
|
+
return (jsx(LinkToEntityPropertyLine, { label: "Attached Node", description: "The scene node this sound is attached to via spatial audio.", entity: attachedNode, selectionService: selectionService }));
|
|
14564
|
+
};
|
|
14565
|
+
|
|
14566
|
+
/**
|
|
14567
|
+
* Renders a clickable "Output Bus" property line for any audio entity that routes to a downstream bus.
|
|
14568
|
+
* @returns The rendered property line.
|
|
14569
|
+
*/
|
|
14570
|
+
const AudioV2OutputBusLink = ({ target, description, selectionService }) => {
|
|
14571
|
+
const outBus = useObservableState(useCallback(() => target.outBus, [target]), useInterceptObservable("property", target, "outBus"));
|
|
14572
|
+
return (jsx(LinkToEntityPropertyLine, { label: "Output Bus", description: description ?? "The bus this entity routes its output to.", entity: outBus, selectionService: selectionService }));
|
|
14573
|
+
};
|
|
14574
|
+
// -----------------------------------------------------------------------------
|
|
14575
|
+
// Engine
|
|
14576
|
+
// -----------------------------------------------------------------------------
|
|
14577
|
+
function useEngineState(engine) {
|
|
14578
|
+
const stateChangedObservables = [
|
|
14579
|
+
useInterceptObservable("function", engine, "pauseAsync"),
|
|
14580
|
+
useInterceptObservable("function", engine, "resumeAsync"),
|
|
14581
|
+
useInterceptObservable("function", engine, "unlockAsync"),
|
|
14582
|
+
];
|
|
14583
|
+
return useObservableState(useCallback(() => engine.state, [engine]), ...stateChangedObservables);
|
|
14584
|
+
}
|
|
14585
|
+
/**
|
|
14586
|
+
* Setup / playback properties for an {@link AudioEngineV2}.
|
|
14587
|
+
* @returns The rendered component.
|
|
14588
|
+
*/
|
|
14589
|
+
const AudioV2EngineGeneralProperties = ({ engine }) => {
|
|
14590
|
+
const state = useEngineState(engine);
|
|
14591
|
+
const volume = useObservableState(useCallback(() => engine.volume, [engine]), useInterceptObservable("function", engine, "setVolume"));
|
|
14592
|
+
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "State", value: state }), jsx(Property, { component: SyncedSliderPropertyLine, label: "Volume", functionPath: "setVolume", value: volume, min: 0, max: 1, step: 0.01, onChange: (value) => engine.setVolume(value) }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Parameter Ramp Duration", target: engine, propertyKey: "parameterRampDuration", min: 0, step: 0.01, unit: "s" })] }));
|
|
14593
|
+
};
|
|
14594
|
+
/**
|
|
14595
|
+
* Resume / pause controls for an {@link AudioEngineV2}.
|
|
14596
|
+
*
|
|
14597
|
+
* No separate Unlock button — `engine.unlockAsync()` is just a thin wrapper around
|
|
14598
|
+
* `engine.resumeAsync()` on the base class, so Resume already covers the autoplay-blocked path.
|
|
14599
|
+
* @returns The rendered component.
|
|
14600
|
+
*/
|
|
14601
|
+
const AudioV2EngineCommandsProperties = ({ engine }) => {
|
|
14602
|
+
const state = useEngineState(engine);
|
|
14603
|
+
return (jsx(Fragment, { children: state === "running" ? (jsx(ButtonLine, { uniqueId: "audiov2-engine-pause", label: "Pause", icon: PauseRegular, onClick: () => void engine.pauseAsync() })) : (jsx(ButtonLine, { uniqueId: "audiov2-engine-resume", label: "Resume", icon: PlayRegular, onClick: () => void engine.resumeAsync() })) }));
|
|
14604
|
+
};
|
|
14605
|
+
/**
|
|
14606
|
+
* Listener spatial-attachment property line for an {@link AudioEngineV2}.
|
|
14607
|
+
* @returns The rendered component.
|
|
14608
|
+
*/
|
|
14609
|
+
const AudioV2EngineListenerProperties = ({ engine, selectionService }) => {
|
|
14610
|
+
const listener = engine.listener;
|
|
14611
|
+
const onAttach = useInterceptObservable("function", listener, "attach");
|
|
14612
|
+
const onDetach = useInterceptObservable("function", listener, "detach");
|
|
14613
|
+
const attachedNode = useObservableState(() => listener.attachedNode, onAttach, onDetach);
|
|
14614
|
+
return (jsx(LinkToEntityPropertyLine, { label: "Attached Node", description: "The scene node the audio listener is attached to via spatial audio.", entity: attachedNode, selectionService: selectionService }));
|
|
14615
|
+
};
|
|
14616
|
+
// -----------------------------------------------------------------------------
|
|
14617
|
+
// Buses (Main + Audio)
|
|
14618
|
+
// -----------------------------------------------------------------------------
|
|
14619
|
+
/**
|
|
14620
|
+
* General properties shared by all v2 audio buses (main and regular).
|
|
14621
|
+
* @returns The rendered component.
|
|
14622
|
+
*/
|
|
14623
|
+
const AudioV2BusGeneralProperties = ({ bus }) => {
|
|
14624
|
+
const volume = useObservableState(useCallback(() => bus.volume, [bus]), useInterceptObservable("function", bus, "setVolume"));
|
|
14625
|
+
return (jsx(Property, { component: SyncedSliderPropertyLine, label: "Volume", functionPath: "setVolume", value: volume, min: 0, max: 1, step: 0.01, onChange: (value) => bus.setVolume(value) }));
|
|
14626
|
+
};
|
|
14627
|
+
/**
|
|
14628
|
+
* Additional properties specific to {@link AudioBus} (a non-main bus that can be routed to another bus).
|
|
14629
|
+
* @returns The rendered component.
|
|
14630
|
+
*/
|
|
14631
|
+
const AudioV2AudioBusGeneralProperties = ({ bus, selectionService }) => {
|
|
14632
|
+
return jsx(AudioV2OutputBusLink, { target: bus, description: "The bus this bus routes its output to.", selectionService: selectionService });
|
|
14633
|
+
};
|
|
14634
|
+
// -----------------------------------------------------------------------------
|
|
14635
|
+
// Sounds (StaticSound + StreamingSound)
|
|
14636
|
+
// -----------------------------------------------------------------------------
|
|
14637
|
+
function GetSoundStateLabel(state) {
|
|
14638
|
+
switch (state) {
|
|
14639
|
+
case 3 /* SoundState.Started */:
|
|
14640
|
+
return "Playing";
|
|
14641
|
+
case 5 /* SoundState.Paused */:
|
|
14642
|
+
return "Paused";
|
|
14643
|
+
case 2 /* SoundState.Starting */:
|
|
14644
|
+
return "Starting";
|
|
14645
|
+
case 0 /* SoundState.Stopping */:
|
|
14646
|
+
return "Stopping";
|
|
14647
|
+
case 4 /* SoundState.FailedToStart */:
|
|
14648
|
+
return "Failed to start";
|
|
14649
|
+
case 1 /* SoundState.Stopped */:
|
|
14650
|
+
default:
|
|
14651
|
+
return "Stopped";
|
|
14652
|
+
}
|
|
14653
|
+
}
|
|
14654
|
+
function useSoundState(sound) {
|
|
14655
|
+
const stateChangedObservables = [
|
|
14656
|
+
useInterceptObservable("function", sound, "play"),
|
|
14657
|
+
useInterceptObservable("function", sound, "pause"),
|
|
14658
|
+
useInterceptObservable("function", sound, "resume"),
|
|
14659
|
+
useInterceptObservable("function", sound, "stop"),
|
|
14660
|
+
// Engine-level hook fires for every state transition on every sound (including async
|
|
14661
|
+
// Starting → Started, FailedToStart, and natural Stopped after stop()), covering changes
|
|
14662
|
+
// that the per-method intercepts above miss.
|
|
14663
|
+
useInterceptObservable("function", sound.engine, "_onSoundPlaybackStateChanged"),
|
|
14664
|
+
];
|
|
14665
|
+
return useObservableState(useCallback(() => sound.state, [sound]), ...stateChangedObservables,
|
|
14666
|
+
// Fires when the sound ends naturally (full duration, non-looping).
|
|
14667
|
+
sound.onEndedObservable);
|
|
14668
|
+
}
|
|
14669
|
+
/**
|
|
14670
|
+
* General properties for any v2 sound.
|
|
14671
|
+
* @returns The rendered component.
|
|
14672
|
+
*/
|
|
14673
|
+
const AudioV2SoundGeneralProperties = ({ sound, selectionService }) => {
|
|
14674
|
+
const state = useSoundState(sound);
|
|
14675
|
+
const volume = useObservableState(useCallback(() => sound.volume, [sound]), useInterceptObservable("function", sound, "setVolume"));
|
|
14676
|
+
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "State", value: GetSoundStateLabel(state) }), jsx(Property, { component: SyncedSliderPropertyLine, label: "Volume", functionPath: "setVolume", value: volume, min: 0, max: 1, step: 0.01, onChange: (value) => sound.setVolume(value) }), jsx(AudioV2OutputBusLink, { target: sound, description: "The bus this sound routes its output to.", selectionService: selectionService })] }));
|
|
14677
|
+
};
|
|
14678
|
+
/**
|
|
14679
|
+
* Playback properties shared by all v2 sounds (loop, start offset, current time).
|
|
14680
|
+
* @returns The rendered component.
|
|
14681
|
+
*/
|
|
14682
|
+
const AudioV2SoundPlaybackProperties = ({ sound }) => {
|
|
14683
|
+
// currentTime advances implicitly as the sound plays — poll to keep the display in sync.
|
|
14684
|
+
// Note: this is total elapsed playback time, not position-within-buffer — it keeps growing
|
|
14685
|
+
// past buffer.duration when looping. That's why it's rendered as a number input rather
|
|
14686
|
+
// than a scrub-style slider.
|
|
14687
|
+
const tickObservable = usePollingObservable(100);
|
|
14688
|
+
const currentTime = useObservableState(useCallback(() => sound.currentTime, [sound]), tickObservable, useInterceptObservable("property", sound, "currentTime"));
|
|
14689
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Loop", target: sound, propertyKey: "loop" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Start Offset", target: sound, propertyKey: "startOffset", min: 0, step: 0.1, unit: "s" }), jsx(Property, { component: NumberInputPropertyLine, label: "Current Time", propertyPath: "currentTime", value: currentTime, min: 0, step: 0.1, unit: "s", onChange: (value) => (sound.currentTime = value) })] }));
|
|
14690
|
+
};
|
|
14691
|
+
/**
|
|
14692
|
+
* Additional playback properties specific to {@link StaticSound} (duration, loop range, pitch, playback rate).
|
|
14693
|
+
* @returns The rendered component.
|
|
14694
|
+
*/
|
|
14695
|
+
const AudioV2StaticSoundPlaybackProperties = ({ sound }) => {
|
|
14696
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Duration", target: sound, propertyKey: "duration", min: 0, step: 0.1, unit: "s" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Loop Start", target: sound, propertyKey: "loopStart", min: 0, step: 0.1, unit: "s" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Loop End", target: sound, propertyKey: "loopEnd", min: 0, step: 0.1, unit: "s" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Pitch", target: sound, propertyKey: "pitch", step: 1, unit: "\u00A2" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Playback Rate", target: sound, propertyKey: "playbackRate", min: 0, step: 0.1 })] }));
|
|
14697
|
+
};
|
|
14698
|
+
/**
|
|
14699
|
+
* Preload status display for {@link StreamingSound}.
|
|
14700
|
+
* @returns The rendered component.
|
|
14701
|
+
*/
|
|
14702
|
+
const AudioV2StreamingSoundPreloadProperties = ({ sound }) => {
|
|
14703
|
+
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Preload Count", value: String(sound.preloadCount) }), jsx(TextPropertyLine, { label: "Preload Completed", value: String(sound.preloadCompletedCount) })] }));
|
|
14704
|
+
};
|
|
14705
|
+
/**
|
|
14706
|
+
* Play / pause / stop controls for any v2 sound.
|
|
14707
|
+
* @returns The rendered component.
|
|
14708
|
+
*/
|
|
14709
|
+
const AudioV2SoundCommandsProperties = ({ sound }) => {
|
|
14710
|
+
const state = useSoundState(sound);
|
|
14711
|
+
const isPlaying = state === 3 /* SoundState.Started */ || state === 2 /* SoundState.Starting */;
|
|
14712
|
+
const isPaused = state === 5 /* SoundState.Paused */;
|
|
14713
|
+
return (jsxs(Fragment, { children: [jsx(ButtonLine, { uniqueId: "audiov2-sound-play-pause", label: isPlaying ? "Pause" : "Play", icon: isPlaying ? PauseRegular : PlayRegular, onClick: () => {
|
|
14714
|
+
if (isPlaying) {
|
|
14715
|
+
sound.pause();
|
|
14716
|
+
}
|
|
14717
|
+
else if (isPaused) {
|
|
14718
|
+
sound.resume();
|
|
14719
|
+
}
|
|
14720
|
+
else {
|
|
14721
|
+
sound.play();
|
|
14722
|
+
}
|
|
14723
|
+
} }), jsx(ButtonLine, { uniqueId: "audiov2-sound-stop", label: "Stop", icon: StopRegular, onClick: () => sound.stop() })] }));
|
|
14724
|
+
};
|
|
14725
|
+
// -----------------------------------------------------------------------------
|
|
14726
|
+
// Standalone sound sources (e.g. microphone)
|
|
14727
|
+
// -----------------------------------------------------------------------------
|
|
14728
|
+
/**
|
|
14729
|
+
* General properties for a v2 sound source that is not a sound (e.g. microphone).
|
|
14730
|
+
* @returns The rendered component.
|
|
14731
|
+
*/
|
|
14732
|
+
const AudioV2SoundSourceGeneralProperties = ({ source, selectionService }) => {
|
|
14733
|
+
const volume = useObservableState(useCallback(() => source.volume, [source]), useInterceptObservable("function", source, "setVolume"));
|
|
14734
|
+
return (jsxs(Fragment, { children: [jsx(Property, { component: SyncedSliderPropertyLine, label: "Volume", functionPath: "setVolume", value: volume, min: 0, max: 1, step: 0.01, onChange: (value) => source.setVolume(value) }), jsx(AudioV2OutputBusLink, { target: source, description: "The bus this source routes its output to.", selectionService: selectionService })] }));
|
|
14735
|
+
};
|
|
14736
|
+
|
|
14289
14737
|
const AudioPropertiesServiceDefinition = {
|
|
14290
14738
|
friendlyName: "Audio Properties",
|
|
14291
|
-
consumes: [PropertiesServiceIdentity],
|
|
14292
|
-
factory: (propertiesService) => {
|
|
14293
|
-
|
|
14739
|
+
consumes: [PropertiesServiceIdentity, SelectionServiceIdentity],
|
|
14740
|
+
factory: (propertiesService, selectionService) => {
|
|
14741
|
+
// --- v1 Sound ---
|
|
14742
|
+
const soundV1ContentRegistration = propertiesService.addSectionContent({
|
|
14294
14743
|
key: "Sound General Properties",
|
|
14295
14744
|
predicate: (entity) => entity instanceof Sound,
|
|
14296
14745
|
content: [
|
|
@@ -14304,9 +14753,121 @@ const AudioPropertiesServiceDefinition = {
|
|
|
14304
14753
|
},
|
|
14305
14754
|
],
|
|
14306
14755
|
});
|
|
14756
|
+
// --- v2 AudioEngineV2 ---
|
|
14757
|
+
const engineV2ContentRegistration = propertiesService.addSectionContent({
|
|
14758
|
+
key: "Audio V2 Engine Properties",
|
|
14759
|
+
predicate: (entity) => entity instanceof AudioEngineV2,
|
|
14760
|
+
content: [
|
|
14761
|
+
{
|
|
14762
|
+
section: "General",
|
|
14763
|
+
component: ({ context }) => jsx(AudioV2EngineGeneralProperties, { engine: context }),
|
|
14764
|
+
},
|
|
14765
|
+
{
|
|
14766
|
+
section: "Listener",
|
|
14767
|
+
component: ({ context }) => jsx(AudioV2EngineListenerProperties, { engine: context, selectionService: selectionService }),
|
|
14768
|
+
},
|
|
14769
|
+
{
|
|
14770
|
+
section: "Commands",
|
|
14771
|
+
component: ({ context }) => jsx(AudioV2EngineCommandsProperties, { engine: context }),
|
|
14772
|
+
},
|
|
14773
|
+
],
|
|
14774
|
+
});
|
|
14775
|
+
// --- v2 Buses (any AbstractAudioBus — covers Main + Audio) ---
|
|
14776
|
+
const busV2ContentRegistration = propertiesService.addSectionContent({
|
|
14777
|
+
key: "Audio V2 Bus Properties",
|
|
14778
|
+
predicate: (entity) => entity instanceof AbstractAudioBus,
|
|
14779
|
+
content: [
|
|
14780
|
+
{
|
|
14781
|
+
section: "General",
|
|
14782
|
+
component: ({ context }) => jsx(AudioV2BusGeneralProperties, { bus: context }),
|
|
14783
|
+
},
|
|
14784
|
+
],
|
|
14785
|
+
});
|
|
14786
|
+
// --- v2 AudioBus (non-main bus; adds an Output Bus link) ---
|
|
14787
|
+
const audioBusV2ContentRegistration = propertiesService.addSectionContent({
|
|
14788
|
+
key: "Audio V2 AudioBus Properties",
|
|
14789
|
+
predicate: (entity) => entity instanceof AudioBus,
|
|
14790
|
+
content: [
|
|
14791
|
+
{
|
|
14792
|
+
section: "General",
|
|
14793
|
+
component: ({ context }) => jsx(AudioV2AudioBusGeneralProperties, { bus: context, selectionService: selectionService }),
|
|
14794
|
+
},
|
|
14795
|
+
],
|
|
14796
|
+
});
|
|
14797
|
+
// --- v2 Sounds (Static + Streaming) ---
|
|
14798
|
+
const soundV2ContentRegistration = propertiesService.addSectionContent({
|
|
14799
|
+
key: "Audio V2 Sound Properties",
|
|
14800
|
+
predicate: (entity) => entity instanceof AbstractSound,
|
|
14801
|
+
content: [
|
|
14802
|
+
{
|
|
14803
|
+
section: "General",
|
|
14804
|
+
component: ({ context }) => jsx(AudioV2SoundGeneralProperties, { sound: context, selectionService: selectionService }),
|
|
14805
|
+
},
|
|
14806
|
+
{
|
|
14807
|
+
section: "Playback",
|
|
14808
|
+
component: ({ context }) => jsx(AudioV2SoundPlaybackProperties, { sound: context }),
|
|
14809
|
+
},
|
|
14810
|
+
{
|
|
14811
|
+
section: "Commands",
|
|
14812
|
+
component: ({ context }) => jsx(AudioV2SoundCommandsProperties, { sound: context }),
|
|
14813
|
+
},
|
|
14814
|
+
],
|
|
14815
|
+
});
|
|
14816
|
+
// --- v2 StaticSound (extra playback properties) ---
|
|
14817
|
+
const staticSoundV2ContentRegistration = propertiesService.addSectionContent({
|
|
14818
|
+
key: "Audio V2 Static Sound Properties",
|
|
14819
|
+
predicate: (entity) => entity instanceof StaticSound,
|
|
14820
|
+
content: [
|
|
14821
|
+
{
|
|
14822
|
+
section: "Playback",
|
|
14823
|
+
component: ({ context }) => jsx(AudioV2StaticSoundPlaybackProperties, { sound: context }),
|
|
14824
|
+
},
|
|
14825
|
+
],
|
|
14826
|
+
});
|
|
14827
|
+
// --- v2 StreamingSound (preload status) ---
|
|
14828
|
+
const streamingSoundV2ContentRegistration = propertiesService.addSectionContent({
|
|
14829
|
+
key: "Audio V2 Streaming Sound Properties",
|
|
14830
|
+
predicate: (entity) => entity instanceof StreamingSound,
|
|
14831
|
+
content: [
|
|
14832
|
+
{
|
|
14833
|
+
section: "Streaming",
|
|
14834
|
+
component: ({ context }) => jsx(AudioV2StreamingSoundPreloadProperties, { sound: context }),
|
|
14835
|
+
},
|
|
14836
|
+
],
|
|
14837
|
+
});
|
|
14838
|
+
// --- v2 Sound Sources (microphone, audio-node) — non-Sound only ---
|
|
14839
|
+
const soundSourceV2ContentRegistration = propertiesService.addSectionContent({
|
|
14840
|
+
key: "Audio V2 Sound Source Properties",
|
|
14841
|
+
predicate: (entity) => entity instanceof AbstractSoundSource && !(entity instanceof AbstractSound),
|
|
14842
|
+
content: [
|
|
14843
|
+
{
|
|
14844
|
+
section: "General",
|
|
14845
|
+
component: ({ context }) => jsx(AudioV2SoundSourceGeneralProperties, { source: context, selectionService: selectionService }),
|
|
14846
|
+
},
|
|
14847
|
+
],
|
|
14848
|
+
});
|
|
14849
|
+
// --- v2 Spatial attachment (any AbstractSoundSource currently spatial) ---
|
|
14850
|
+
const spatialV2ContentRegistration = propertiesService.addSectionContent({
|
|
14851
|
+
key: "Audio V2 Spatial Properties",
|
|
14852
|
+
predicate: (entity) => entity instanceof AbstractSoundSource && entity._isSpatial,
|
|
14853
|
+
content: [
|
|
14854
|
+
{
|
|
14855
|
+
section: "Spatial",
|
|
14856
|
+
component: ({ context }) => jsx(AudioV2SpatialAttachmentProperties, { source: context, selectionService: selectionService }),
|
|
14857
|
+
},
|
|
14858
|
+
],
|
|
14859
|
+
});
|
|
14307
14860
|
return {
|
|
14308
14861
|
dispose: () => {
|
|
14309
|
-
|
|
14862
|
+
soundV1ContentRegistration.dispose();
|
|
14863
|
+
engineV2ContentRegistration.dispose();
|
|
14864
|
+
busV2ContentRegistration.dispose();
|
|
14865
|
+
audioBusV2ContentRegistration.dispose();
|
|
14866
|
+
soundV2ContentRegistration.dispose();
|
|
14867
|
+
staticSoundV2ContentRegistration.dispose();
|
|
14868
|
+
streamingSoundV2ContentRegistration.dispose();
|
|
14869
|
+
soundSourceV2ContentRegistration.dispose();
|
|
14870
|
+
spatialV2ContentRegistration.dispose();
|
|
14310
14871
|
},
|
|
14311
14872
|
};
|
|
14312
14873
|
},
|
|
@@ -14740,7 +15301,7 @@ function useObservableArray(target, getItems, addFn, removeFn, changeFn) {
|
|
|
14740
15301
|
}, [getItems]), useInterceptObservable("function", target, addFn), useInterceptObservable("function", target, removeFn), changeFn ? useInterceptObservable("function", target, changeFn) : undefined);
|
|
14741
15302
|
}
|
|
14742
15303
|
|
|
14743
|
-
const useStyles$
|
|
15304
|
+
const useStyles$q = makeStyles({
|
|
14744
15305
|
lightsListDiv: {
|
|
14745
15306
|
display: "flex",
|
|
14746
15307
|
flexDirection: "column",
|
|
@@ -14750,7 +15311,7 @@ const ClusteredLightContainerSetupProperties = ({ context: container }) => {
|
|
|
14750
15311
|
return (jsxs(Fragment, { children: [jsx(BooleanBadgePropertyLine, { label: "Is Supported", value: container.isSupported }), jsx(BoundProperty, { label: "Horizontal Tiles", component: NumberInputPropertyLine, target: container, propertyKey: "horizontalTiles", step: 1, min: 1, forceInt: true }), jsx(BoundProperty, { label: "Vertical Tiles", component: NumberInputPropertyLine, target: container, propertyKey: "verticalTiles", step: 1, min: 1, forceInt: true }), jsx(BoundProperty, { label: "Depth Slices", component: NumberInputPropertyLine, target: container, propertyKey: "depthSlices", step: 1, min: 1, forceInt: true }), jsx(BoundProperty, { label: "Max Range", component: NumberInputPropertyLine, target: container, propertyKey: "maxRange", min: 1 })] }));
|
|
14751
15312
|
};
|
|
14752
15313
|
const ClusteredLightContainerLightsProperties = ({ container, selectionService, }) => {
|
|
14753
|
-
const classes = useStyles$
|
|
15314
|
+
const classes = useStyles$q();
|
|
14754
15315
|
const lights = useObservableArray(container, useCallback(() => container.lights, [container]), "addLight", "removeLight");
|
|
14755
15316
|
return (jsx(PropertyLine, { label: "Lights", expandedContent: jsx("div", { className: classes.lightsListDiv, children: lights.map((light) => (jsx(LinkToEntityPropertyLine, { label: light.getClassName(), entity: light, selectionService: selectionService }, light.uniqueId))) }), children: jsx(Badge, { appearance: "filled", children: lights.length }) }));
|
|
14756
15317
|
};
|
|
@@ -14800,7 +15361,7 @@ const HemisphericLightSetupProperties = ({ context: hemisphericLight }) => {
|
|
|
14800
15361
|
return (jsxs(Fragment, { children: [jsx(BoundProperty, { label: "Direction", component: Vector3PropertyLine, target: hemisphericLight, propertyKey: "direction" }), jsx(BoundProperty, { label: "Diffuse", component: Color3PropertyLine, target: hemisphericLight, propertyKey: "diffuse" }), jsx(BoundProperty, { label: "Ground", component: Color3PropertyLine, target: hemisphericLight, propertyKey: "groundColor" }), jsx(BoundProperty, { label: "Intensity", component: NumberInputPropertyLine, target: hemisphericLight, propertyKey: "intensity" })] }));
|
|
14801
15362
|
};
|
|
14802
15363
|
|
|
14803
|
-
const useStyles$
|
|
15364
|
+
const useStyles$p = makeStyles({
|
|
14804
15365
|
root: {
|
|
14805
15366
|
display: "grid",
|
|
14806
15367
|
gridTemplateRows: "repeat(1fr)",
|
|
@@ -14830,7 +15391,7 @@ const useStyles$o = makeStyles({
|
|
|
14830
15391
|
const ComboBox = forwardRef((props, ref) => {
|
|
14831
15392
|
ComboBox.displayName = "ComboBox";
|
|
14832
15393
|
const comboId = useId();
|
|
14833
|
-
const styles = useStyles$
|
|
15394
|
+
const styles = useStyles$p();
|
|
14834
15395
|
const { size } = useContext(ToolContext);
|
|
14835
15396
|
// Find the label for the current value
|
|
14836
15397
|
const getLabel = (value) => props.options.find((opt) => opt.value === value)?.label ?? "";
|
|
@@ -14853,7 +15414,7 @@ const ComboBox = forwardRef((props, ref) => {
|
|
|
14853
15414
|
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 })] }));
|
|
14854
15415
|
});
|
|
14855
15416
|
|
|
14856
|
-
const useStyles$
|
|
15417
|
+
const useStyles$o = makeStyles({
|
|
14857
15418
|
linkDiv: {
|
|
14858
15419
|
display: "flex",
|
|
14859
15420
|
flexDirection: "row",
|
|
@@ -14878,7 +15439,7 @@ const useStyles$n = makeStyles({
|
|
|
14878
15439
|
function EntitySelector(props) {
|
|
14879
15440
|
const { value, onLink, getEntities, getName, filter, defaultValue } = props;
|
|
14880
15441
|
const onChange = props.onChange;
|
|
14881
|
-
const classes = useStyles$
|
|
15442
|
+
const classes = useStyles$o();
|
|
14882
15443
|
const comboBoxRef = useRef(null);
|
|
14883
15444
|
// Build options with uniqueId as key
|
|
14884
15445
|
const options = useMemo(() => {
|
|
@@ -15032,7 +15593,7 @@ const TextureUpload = (props) => {
|
|
|
15032
15593
|
return jsx(UploadButton, { onUpload: handleUpload, accept: accept, title: "Upload Texture", label: label });
|
|
15033
15594
|
};
|
|
15034
15595
|
|
|
15035
|
-
const useStyles$
|
|
15596
|
+
const useStyles$n = makeStyles({
|
|
15036
15597
|
container: {
|
|
15037
15598
|
display: "flex",
|
|
15038
15599
|
flexDirection: "row",
|
|
@@ -15049,7 +15610,7 @@ const useStyles$m = makeStyles({
|
|
|
15049
15610
|
const TextureSelector = (props) => {
|
|
15050
15611
|
TextureSelector.displayName = "TextureSelector";
|
|
15051
15612
|
const { scene, cubeOnly, value, onChange, onLink, defaultValue } = props;
|
|
15052
|
-
const classes = useStyles$
|
|
15613
|
+
const classes = useStyles$n();
|
|
15053
15614
|
const getTextures = useCallback(() => scene.textures, [scene.textures]);
|
|
15054
15615
|
const getName = useCallback((texture) => texture.displayName || texture.name || `${texture.getClassName() || "Unnamed Texture"} (${texture.uniqueId})`, []);
|
|
15055
15616
|
const filter = useCallback((texture) => !cubeOnly || texture.isCube, [cubeOnly]);
|
|
@@ -15654,7 +16215,7 @@ async function EditNodeMaterial(material) {
|
|
|
15654
16215
|
await material.edit({ nodeEditorConfig: { backgroundColor: material.getScene().clearColor } });
|
|
15655
16216
|
}
|
|
15656
16217
|
|
|
15657
|
-
const useStyles$
|
|
16218
|
+
const useStyles$m = makeStyles({
|
|
15658
16219
|
subsection: {
|
|
15659
16220
|
marginTop: tokens.spacingVerticalM,
|
|
15660
16221
|
},
|
|
@@ -15728,7 +16289,7 @@ const GradientBlockPropertyLine = (props) => {
|
|
|
15728
16289
|
};
|
|
15729
16290
|
const NodeMaterialInputProperties = (props) => {
|
|
15730
16291
|
const { material } = props;
|
|
15731
|
-
const classes = useStyles$
|
|
16292
|
+
const classes = useStyles$m();
|
|
15732
16293
|
const inputBlocks = useObservableState(useCallback(() => {
|
|
15733
16294
|
const inspectorVisibleInputBlocks = material
|
|
15734
16295
|
.getInputBlocks()
|
|
@@ -15790,6 +16351,115 @@ const CheckboxPropertyLine = (props) => {
|
|
|
15790
16351
|
return (jsx(PropertyLine, { ...props, children: jsx(Checkbox, { ...props }) }));
|
|
15791
16352
|
};
|
|
15792
16353
|
|
|
16354
|
+
const useStyles$l = makeStyles({
|
|
16355
|
+
expandedDebugContainer: {
|
|
16356
|
+
display: "flex",
|
|
16357
|
+
alignItems: "center",
|
|
16358
|
+
marginTop: tokens.spacingVerticalXS,
|
|
16359
|
+
},
|
|
16360
|
+
debugLabel: {
|
|
16361
|
+
flex: 1,
|
|
16362
|
+
},
|
|
16363
|
+
});
|
|
16364
|
+
/**
|
|
16365
|
+
* Toggles debug mode for a texture on a material.
|
|
16366
|
+
* When enabled, creates a debug `StandardMaterial` with the texture wired as `emissiveTexture` and swaps it onto every
|
|
16367
|
+
* mesh that currently uses the original material. Enabling debug for one texture on a material disables it for any
|
|
16368
|
+
* other texture on that material (mutually exclusive).
|
|
16369
|
+
*
|
|
16370
|
+
* Notes:
|
|
16371
|
+
* - The texture is rendered using its current `level`. Textures whose level is not 1 will appear modulated; this is
|
|
16372
|
+
* intentional so that no global state on the source texture is mutated (a level mutation would affect every other
|
|
16373
|
+
* material that references the same texture instance).
|
|
16374
|
+
* - Only meshes referencing the original material at toggle time receive the debug material. Meshes added or
|
|
16375
|
+
* reassigned to the original material afterwards are not affected until the next toggle cycle.
|
|
16376
|
+
* @param material - The material to debug
|
|
16377
|
+
* @param texture - The texture to debug
|
|
16378
|
+
* @param enable - Whether to enable or disable debug mode
|
|
16379
|
+
*/
|
|
16380
|
+
function ToggleTextureDebug(material, texture, enable) {
|
|
16381
|
+
if (!material || !texture) {
|
|
16382
|
+
return;
|
|
16383
|
+
}
|
|
16384
|
+
const scene = material.getScene();
|
|
16385
|
+
material.reservedDataStore ?? (material.reservedDataStore = {});
|
|
16386
|
+
const store = material.reservedDataStore;
|
|
16387
|
+
store.debugTexture ?? (store.debugTexture = null);
|
|
16388
|
+
store.debugMaterial ?? (store.debugMaterial = null);
|
|
16389
|
+
const isCurrentlyDebugging = store.debugTexture === texture;
|
|
16390
|
+
if (enable && !isCurrentlyDebugging) {
|
|
16391
|
+
// If we were debugging a different texture, clean it up first.
|
|
16392
|
+
if (store.debugTexture) {
|
|
16393
|
+
ToggleTextureDebug(material, store.debugTexture, false);
|
|
16394
|
+
}
|
|
16395
|
+
const debugMaterial = new StandardMaterial("debugMaterial", scene);
|
|
16396
|
+
debugMaterial.disableLighting = true;
|
|
16397
|
+
debugMaterial.sideOrientation = material.sideOrientation;
|
|
16398
|
+
debugMaterial.emissiveTexture = texture;
|
|
16399
|
+
debugMaterial.forceDepthWrite = true;
|
|
16400
|
+
debugMaterial.reservedDataStore = { hidden: true };
|
|
16401
|
+
for (const mesh of scene.meshes) {
|
|
16402
|
+
if (mesh.material === material) {
|
|
16403
|
+
mesh.material = debugMaterial;
|
|
16404
|
+
}
|
|
16405
|
+
}
|
|
16406
|
+
store.debugMaterial = debugMaterial;
|
|
16407
|
+
// Assign debugTexture LAST so observers see a fully-populated store.
|
|
16408
|
+
store.debugTexture = texture;
|
|
16409
|
+
}
|
|
16410
|
+
else if (!enable && isCurrentlyDebugging) {
|
|
16411
|
+
const debugMaterial = store.debugMaterial;
|
|
16412
|
+
if (debugMaterial) {
|
|
16413
|
+
for (const mesh of scene.meshes) {
|
|
16414
|
+
if (mesh.material === debugMaterial) {
|
|
16415
|
+
mesh.material = material;
|
|
16416
|
+
}
|
|
16417
|
+
}
|
|
16418
|
+
debugMaterial.dispose();
|
|
16419
|
+
store.debugMaterial = null;
|
|
16420
|
+
}
|
|
16421
|
+
store.debugTexture = null;
|
|
16422
|
+
}
|
|
16423
|
+
}
|
|
16424
|
+
/**
|
|
16425
|
+
* A texture selector property line with material texture debug capability.
|
|
16426
|
+
* Displays a debug toggle in expanded content to render the selected texture as emissive on the material.
|
|
16427
|
+
* Enabling debug on one texture for a given material disables it for any other texture on that material.
|
|
16428
|
+
* @param props - The texture selector property line props plus material reference
|
|
16429
|
+
* @returns The property line element with debug toggle
|
|
16430
|
+
*/
|
|
16431
|
+
const MaterialTextureDebugPropertyLine = (props) => {
|
|
16432
|
+
const classes = useStyles$l();
|
|
16433
|
+
const { material, ...textureProps } = props;
|
|
16434
|
+
const texture = props.value;
|
|
16435
|
+
const reservedDataStore = useProperty(material, "reservedDataStore");
|
|
16436
|
+
const debugTexture = useProperty(reservedDataStore, "debugTexture");
|
|
16437
|
+
const isDebugEnabled = !!texture && debugTexture === texture;
|
|
16438
|
+
// Track the texture this slot last rendered with so we can detect when its value changes away
|
|
16439
|
+
// from the texture currently being debugged. Without this, reassigning the slot's texture (or
|
|
16440
|
+
// setting it to null) while debug is active would leave the scene stuck in debug view with no
|
|
16441
|
+
// visible toggle to turn it off (the toggle for that slot is keyed off texture-instance
|
|
16442
|
+
// equality and would just appear off).
|
|
16443
|
+
const prevTextureRef = useRef(texture);
|
|
16444
|
+
useEffect(() => {
|
|
16445
|
+
const prevTexture = prevTextureRef.current;
|
|
16446
|
+
prevTextureRef.current = texture;
|
|
16447
|
+
if (prevTexture && prevTexture !== texture) {
|
|
16448
|
+
const store = material.reservedDataStore;
|
|
16449
|
+
if (store?.debugTexture === prevTexture) {
|
|
16450
|
+
ToggleTextureDebug(material, prevTexture, false);
|
|
16451
|
+
}
|
|
16452
|
+
}
|
|
16453
|
+
}, [texture]);
|
|
16454
|
+
const handleDebugToggle = useCallback((checked) => {
|
|
16455
|
+
if (texture) {
|
|
16456
|
+
ToggleTextureDebug(material, texture, checked);
|
|
16457
|
+
}
|
|
16458
|
+
}, [material, texture]);
|
|
16459
|
+
const expandedContent = texture ? (jsxs("div", { className: classes.expandedDebugContainer, children: [jsx("span", { className: classes.debugLabel, children: "Display Texture for Debug" }), jsx(Switch, { value: isDebugEnabled, onChange: handleDebugToggle })] })) : undefined;
|
|
16460
|
+
return (jsx(PropertyLine, { ...textureProps, expandedContent: expandedContent, children: jsx(TextureSelector, { ...textureProps }) }));
|
|
16461
|
+
};
|
|
16462
|
+
|
|
15793
16463
|
const LightFalloffOptions = [
|
|
15794
16464
|
{ label: "Physical", value: PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL },
|
|
15795
16465
|
{ label: "glTF", value: PBRBaseMaterial.LIGHTFALLOFF_GLTF },
|
|
@@ -15894,7 +16564,7 @@ const PBRBaseMaterialChannelsProperties = (props) => {
|
|
|
15894
16564
|
const { material, selectionService } = props;
|
|
15895
16565
|
const scene = material.getScene();
|
|
15896
16566
|
const selectEntity = (entity) => (selectionService.selectedEntity = entity);
|
|
15897
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component:
|
|
16567
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Albedo", target: material, propertyKey: "_albedoTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Base Weight", target: material, propertyKey: "_baseWeightTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughnessTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Metallic Roughness", target: material, propertyKey: "_metallicTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, uniqueId: "PBRBaseMaterialChannels_Reflection", label: "Reflection", target: material, propertyKey: "_reflectionTexture", scene: scene, cubeOnly: true, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Refraction", target: material.subSurface, propertyKey: "refractionTexture", propertyPath: "subSurface.refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Reflectivity", target: material, propertyKey: "_reflectivityTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Micro Surface", target: material, propertyKey: "_microSurfaceTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Bump", target: material, propertyKey: "_bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Emissive", target: material, propertyKey: "_emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Opacity", target: material, propertyKey: "_opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Ambient", target: material, propertyKey: "_ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Lightmap", target: material, propertyKey: "_lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Detailmap", target: material.detailMap, propertyKey: "texture", propertyPath: "detailMap.texture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Lightmap as Shadowmap", target: material, propertyKey: "_useLightmapAsShadowmap" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Detailmap", target: material.detailMap, propertyKey: "isEnabled", propertyPath: "detailMap.isEnabled" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Decalmap", target: material.decalMap, propertyKey: "isEnabled", propertyPath: "decalMap.isEnabled" })] }));
|
|
15898
16568
|
};
|
|
15899
16569
|
const PBRBaseMaterialLightingAndColorProperties = (props) => {
|
|
15900
16570
|
const { material } = props;
|
|
@@ -15904,7 +16574,7 @@ const PBRBaseMaterialMetallicWorkflowProperties = (props) => {
|
|
|
15904
16574
|
const { material, selectionService } = props;
|
|
15905
16575
|
const scene = material.getScene();
|
|
15906
16576
|
const selectEntity = (entity) => (selectionService.selectedEntity = entity);
|
|
15907
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Metallic", target: material, propertyKey: "_metallic", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, uniqueId: "PBRBaseMaterialMetallicWorkflow_Roughness", label: "Roughness", target: material, propertyKey: "_roughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Index of Refraction", target: material.subSurface, propertyKey: "indexOfRefraction", propertyPath: "subSurface.indexOfRefraction", min: 1, max: 3, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "F0 Factor", target: material, propertyKey: "_metallicF0Factor", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Reflectance Color", target: material, propertyKey: "_metallicReflectanceColor", isLinearMode: true }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Metallic Only", description: "Use only metallic from MetallicReflectance texture", target: material, propertyKey: "_useOnlyMetallicFromMetallicReflectanceTexture" }), jsx(BoundProperty, { component:
|
|
16577
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Metallic", target: material, propertyKey: "_metallic", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, uniqueId: "PBRBaseMaterialMetallicWorkflow_Roughness", label: "Roughness", target: material, propertyKey: "_roughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "_baseDiffuseRoughness", min: 0, max: 1, step: 0.01, nullable: true, defaultValue: 0 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Index of Refraction", target: material.subSurface, propertyKey: "indexOfRefraction", propertyPath: "subSurface.indexOfRefraction", min: 1, max: 3, step: 0.01 }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "F0 Factor", target: material, propertyKey: "_metallicF0Factor", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Reflectance Color", target: material, propertyKey: "_metallicReflectanceColor", isLinearMode: true }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Metallic Only", description: "Use only metallic from MetallicReflectance texture", target: material, propertyKey: "_useOnlyMetallicFromMetallicReflectanceTexture" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Metallic Reflectance", target: material, propertyKey: "_metallicReflectanceTexture", material: material, scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Reflectance", target: material, propertyKey: "_reflectanceTexture", material: material, scene: scene, onLink: selectEntity, defaultValue: null })] }));
|
|
15908
16578
|
};
|
|
15909
16579
|
const PBRBaseMaterialClearCoatProperties = (props) => {
|
|
15910
16580
|
const { material, selectionService } = props;
|
|
@@ -15971,7 +16641,7 @@ const PBRBaseMaterialDebugProperties = (props) => {
|
|
|
15971
16641
|
*/
|
|
15972
16642
|
const OpenPBRMaterialBaseProperties = (props) => {
|
|
15973
16643
|
const { material } = props;
|
|
15974
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Weight", target: material, propertyKey: "baseWeight", min: 0, max: 1, step: 0.01, description: "Controls how strong or visible the base aspect appears.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component:
|
|
16644
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Weight", target: material, propertyKey: "baseWeight", min: 0, max: 1, step: 0.01, description: "Controls how strong or visible the base aspect appears.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Base Weight", target: material, propertyKey: "baseWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Base Color", target: material, propertyKey: "baseColor", isLinearMode: true, description: "Sets the primary surface color of the material.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Base Color", target: material, propertyKey: "baseColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Metalness", target: material, propertyKey: "baseMetalness", min: 0, max: 1, step: 0.01, description: "Controls whether the material behaves as metal or non-metal. The parameter supersedes transmission_weight and subsurface_weight.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Base Metalness", target: material, propertyKey: "baseMetalnessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "baseDiffuseRoughness", min: 0, max: 1, step: 0.01, description: "Softens the surface's base appearance. Higher values create matte or porous looks. Lower values are smoother.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "baseDiffuseRoughnessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Ambient Occlusion", target: material, propertyKey: "ambientOcclusionTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material })] }));
|
|
15975
16645
|
};
|
|
15976
16646
|
/**
|
|
15977
16647
|
* Displays the specular layer properties of an OpenPBR material.
|
|
@@ -15980,15 +16650,15 @@ const OpenPBRMaterialBaseProperties = (props) => {
|
|
|
15980
16650
|
*/
|
|
15981
16651
|
const OpenPBRMaterialSpecularProperties = (props) => {
|
|
15982
16652
|
const { material } = props;
|
|
15983
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Specular Weight", target: material, propertyKey: "specularWeight", min: 0, max: 1, step: 0.01, description: "Controls how strong the reflections appear.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component:
|
|
16653
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Specular Weight", target: material, propertyKey: "specularWeight", min: 0, max: 1, step: 0.01, description: "Controls how strong the reflections appear.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Specular Weight", target: material, propertyKey: "specularWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Specular Color", target: material, propertyKey: "specularColor", isLinearMode: true, description: "Tints the color of reflections.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Specular Color", target: material, propertyKey: "specularColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Specular Roughness", target: material, propertyKey: "specularRoughness", min: 0, max: 1, step: 0.01, description: "Controls how sharp or blurry reflections are.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Specular Roughness", target: material, propertyKey: "specularRoughnessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Specular Roughness Anisotropy", target: material, propertyKey: "specularRoughnessAnisotropy", min: 0, max: 1, step: 0.01, description: "Stretches reflections in one direction for brushed or streaked looks. Requires specular_roughness > 0.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/microfacetmodel" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Specular Roughness Anisotropy", target: material, propertyKey: "specularRoughnessAnisotropyTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Specular IOR", target: material, propertyKey: "specularIor", min: 1, max: 30, step: 0.01, description: "Index of refraction is a physical value controlling the reflective intensity and refraction. The parameter has no effect on metals.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate" })] }));
|
|
15984
16654
|
};
|
|
15985
16655
|
const OpenPBRMaterialTransmissionProperties = (props) => {
|
|
15986
16656
|
const { material } = props;
|
|
15987
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Transmission Weight", target: material, propertyKey: "transmissionWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the transparency effect. The parameter is superseded by base_metalness.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component:
|
|
16657
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Transmission Weight", target: material, propertyKey: "transmissionWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the transparency effect. The parameter is superseded by base_metalness.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Transmission Weight", target: material, propertyKey: "transmissionWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Transmission Color", target: material, propertyKey: "transmissionColor", isLinearMode: true, description: "Tints light passing through the material. Works with transmission_depth for realistic thickness-based coloring.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Transmission Color", target: material, propertyKey: "transmissionColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Transmission Depth (cm)", target: material, propertyKey: "transmissionDepth", min: 0, max: 50, step: 0.001, convertTo: (value) => value * 100, convertFrom: (value) => value / 100, description: "Controls how quickly light is absorbed with thickness. Distance is in scene units.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Transmission Depth", target: material, propertyKey: "transmissionDepthTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Transmission Scatter", target: material, propertyKey: "transmissionScatter", isLinearMode: true, description: "Adds internal cloudiness to create materials like juice, honey, etc. Requires transmission_depth > 0.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Transmission Scatter", target: material, propertyKey: "transmissionScatterTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Transmission Scatter Anisotropy", target: material, propertyKey: "transmissionScatterAnisotropy", min: -1, max: 1, step: 0.01, description: "Shifts scattering forward/backward for clearer or hazier appearance depending on viewing angle.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Transmission Dispersion Abbe Number", target: material, propertyKey: "transmissionDispersionAbbeNumber", min: 1, max: 100, step: 1, description: "Physical value for the rainbow color separation in refraction.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Transmission Dispersion Scale", target: material, propertyKey: "transmissionDispersionScale", min: 0, max: 5, step: 0.01, description: "Strength of rainbow color separation in refraction.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/translucentbase" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Transmission Dispersion Scale", target: material, propertyKey: "transmissionDispersionScaleTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material })] }));
|
|
15988
16658
|
};
|
|
15989
16659
|
const OpenPBRMaterialSubsurfaceProperties = (props) => {
|
|
15990
16660
|
const { material } = props;
|
|
15991
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Subsurface Weight", target: material, propertyKey: "subsurfaceWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the subsurface effect. The parameter is superseded by base_metalness and transmission_weight.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/subsurface" }), jsx(BoundProperty, { component:
|
|
16661
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Subsurface Weight", target: material, propertyKey: "subsurfaceWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the subsurface effect. The parameter is superseded by base_metalness and transmission_weight.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/subsurface" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Subsurface Weight", target: material, propertyKey: "subsurfaceWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Subsurface Color", target: material, propertyKey: "subsurfaceColor", isLinearMode: true, description: "Colors the light that scatters under the surface.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/subsurface" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Subsurface Color", target: material, propertyKey: "subsurfaceColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Subsurface Radius (cm)", target: material, propertyKey: "subsurfaceRadius", min: 0, max: 50, step: 0.001, convertTo: (value) => value * 100, convertFrom: (value) => value / 100, description: "Controls how soft and spread-out the subsurface look appears.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/subsurface" }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Subsurface Radius Scale", target: material, propertyKey: "subsurfaceRadiusScale", isLinearMode: true, description: "Tints thin areas with light shining through, like warm glow on ears or leaves.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/subsurface" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Subsurface Radius Scale", target: material, propertyKey: "subsurfaceRadiusScaleTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Subsurface Scatter Anisotropy", target: material, propertyKey: "subsurfaceScatterAnisotropy", min: -1, max: 1, step: 0.01, description: "Shifts scattering forward/backward for a softer glow or a sharper one.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/basesubstrate/subsurface" })] }));
|
|
15992
16662
|
};
|
|
15993
16663
|
/**
|
|
15994
16664
|
* Displays the coat layer properties of an OpenPBR material.
|
|
@@ -15997,7 +16667,7 @@ const OpenPBRMaterialSubsurfaceProperties = (props) => {
|
|
|
15997
16667
|
*/
|
|
15998
16668
|
const OpenPBRMaterialCoatProperties = (props) => {
|
|
15999
16669
|
const { material } = props;
|
|
16000
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat Weight", target: material, propertyKey: "coatWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the coat.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat" }), jsx(BoundProperty, { component:
|
|
16670
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat Weight", target: material, propertyKey: "coatWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the coat.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Coat Weight", target: material, propertyKey: "coatWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Coat Color", target: material, propertyKey: "coatColor", isLinearMode: true, description: "Tints the coat, for tinted varnish or paint.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Coat Color", target: material, propertyKey: "coatColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat Roughness", target: material, propertyKey: "coatRoughness", min: 0, max: 1, step: 0.01, description: "Controls how sharp or blurry the coat reflections appear.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat/roughening" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Coat Roughness", target: material, propertyKey: "coatRoughnessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat Roughness Anisotropy", target: material, propertyKey: "coatRoughnessAnisotropy", min: 0, max: 1, step: 0.01, description: "Stretches coat reflections in one direction for brushed or streaked looks. Requires coat_roughness > 0.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Coat Roughness Anisotropy", target: material, propertyKey: "coatRoughnessAnisotropyTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat IOR", target: material, propertyKey: "coatIor", min: 1, max: 3, step: 0.01, description: "Index of refraction is a physical value controlling the reflective intensity of the coat.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat" }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat Darkening", target: material, propertyKey: "coatDarkening", min: 0, max: 1, step: 0.01, description: "Darkens the base under the coat, similar to how real varnish deepens color.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat/darkening" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Coat Darkening", target: material, propertyKey: "coatDarkeningTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material })] }));
|
|
16001
16671
|
};
|
|
16002
16672
|
/**
|
|
16003
16673
|
* Displays the fuzz layer properties of an OpenPBR material.
|
|
@@ -16006,7 +16676,7 @@ const OpenPBRMaterialCoatProperties = (props) => {
|
|
|
16006
16676
|
*/
|
|
16007
16677
|
const OpenPBRMaterialFuzzProperties = (props) => {
|
|
16008
16678
|
const { material } = props;
|
|
16009
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Fuzz Weight", target: material, propertyKey: "fuzzWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the fuzz.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/fuzz" }), jsx(BoundProperty, { component:
|
|
16679
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Fuzz Weight", target: material, propertyKey: "fuzzWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the fuzz.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/fuzz" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Fuzz Weight", target: material, propertyKey: "fuzzWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: Color3PropertyLine, label: "Fuzz Color", target: material, propertyKey: "fuzzColor", isLinearMode: true, description: "Controls the color of the fuzz.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/fuzz" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Fuzz Color", target: material, propertyKey: "fuzzColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Fuzz Roughness", target: material, propertyKey: "fuzzRoughness", min: 0, max: 1, step: 0.01, description: "Controls the roughness of the fuzz.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/fuzz" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Fuzz Roughness", target: material, propertyKey: "fuzzRoughnessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material })] }));
|
|
16010
16680
|
};
|
|
16011
16681
|
/**
|
|
16012
16682
|
* Displays the emission properties of an OpenPBR material.
|
|
@@ -16015,7 +16685,7 @@ const OpenPBRMaterialFuzzProperties = (props) => {
|
|
|
16015
16685
|
*/
|
|
16016
16686
|
const OpenPBRMaterialEmissionProperties = (props) => {
|
|
16017
16687
|
const { material } = props;
|
|
16018
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Color3PropertyLine, label: "Emission Color", target: material, propertyKey: "emissionColor", isLinearMode: true, description: "Controls the color of the glow.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/emission" }), jsx(BoundProperty, { component:
|
|
16688
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Color3PropertyLine, label: "Emission Color", target: material, propertyKey: "emissionColor", isLinearMode: true, description: "Controls the color of the glow.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/emission" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Emission Color", target: material, propertyKey: "emissionColorTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Emission Luminance", target: material, propertyKey: "emissionLuminance", min: 0, max: 10, step: 0.01, description: "Controls how bright the glow is.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/emission" })] }));
|
|
16019
16689
|
};
|
|
16020
16690
|
/**
|
|
16021
16691
|
* Displays the thin film properties of an OpenPBR material.
|
|
@@ -16024,7 +16694,7 @@ const OpenPBRMaterialEmissionProperties = (props) => {
|
|
|
16024
16694
|
*/
|
|
16025
16695
|
const OpenPBRMaterialThinFilmProperties = (props) => {
|
|
16026
16696
|
const { material } = props;
|
|
16027
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Thin Film Weight", target: material, propertyKey: "thinFilmWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the thin-film.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/thin-filmiridescence" }), jsx(BoundProperty, { component:
|
|
16697
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Thin Film Weight", target: material, propertyKey: "thinFilmWeight", min: 0, max: 1, step: 0.01, description: "Controls the presence of the thin-film.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/thin-filmiridescence" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Thin Film Weight", target: material, propertyKey: "thinFilmWeightTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Thin Film Thickness", target: material, propertyKey: "thinFilmThickness", min: 0, max: 1, step: 0.01, description: "Changes the color pattern of the iridescence.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/thin-filmiridescence" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Thin Film Thickness", target: material, propertyKey: "thinFilmThicknessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Thin Film IOR", target: material, propertyKey: "thinFilmIor", min: 1, max: 3, step: 0.01, description: "Alters the strength and contrast of the color shift based in the index of refraction.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/thin-filmiridescence" })] }));
|
|
16028
16698
|
};
|
|
16029
16699
|
/**
|
|
16030
16700
|
* Displays the geometry properties of an OpenPBR material.
|
|
@@ -16033,7 +16703,7 @@ const OpenPBRMaterialThinFilmProperties = (props) => {
|
|
|
16033
16703
|
*/
|
|
16034
16704
|
const OpenPBRMaterialGeometryProperties = (props) => {
|
|
16035
16705
|
const { material } = props;
|
|
16036
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Geometry Opacity", target: material, propertyKey: "geometryOpacity", min: 0, max: 1, step: 0.01, description: "Controls material presence and transparency cutout.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/opacity/transparency" }), jsx(BoundProperty, { component:
|
|
16706
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Geometry Opacity", target: material, propertyKey: "geometryOpacity", min: 0, max: 1, step: 0.01, description: "Controls material presence and transparency cutout.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/opacity/transparency" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Geometry Opacity", target: material, propertyKey: "geometryOpacityTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: CheckboxPropertyLine, label: "Thin-Walled", target: material, propertyKey: "geometryThinWalled", description: "When enabled, treats material as a thin shell (like leaves, paper sheets or windows). Disables ray bending in refraction.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/thin-walledcase" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Geometry Normal", target: material, propertyKey: "geometryNormalTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Tangent Angle", target: material, propertyKey: "geometryTangentAngle", min: 0, max: Math.PI, step: 0.01, description: "Tangent vector controlling anisotropic reflection direction for the base (metal and non-metal). Works with specular_roughness_anisotropy.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/geometry/tangent" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Geometry Tangent", target: material, propertyKey: "geometryTangentTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Coat Tangent Angle", target: material, propertyKey: "geometryCoatTangentAngle", min: 0, max: Math.PI, step: 0.01, description: "Tangent vector controlling anisotropic reflection direction for the coat. Works with coat_roughness_anisotropy.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/geometry/coat-tangent" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Geometry Coat Normal", target: material, propertyKey: "geometryCoatNormalTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Geometry Coat Tangent", target: material, propertyKey: "geometryCoatTangentTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material }), jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "Geometry Thickness", target: material, propertyKey: "geometryThickness", min: 0, step: 0.001, description: "Controls the thickness of the geometry for volume approximations.", docLink: "https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/thickness" }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Geometry Thickness", target: material, propertyKey: "geometryThicknessTexture", scene: material.getScene(), defaultValue: null, onLink: (texture) => void 0, material: material })] }));
|
|
16037
16707
|
};
|
|
16038
16708
|
const SssQualityOptions = [
|
|
16039
16709
|
{ label: "Low (8 samples)", value: 0 },
|
|
@@ -16068,7 +16738,7 @@ const StandardMaterialTexturesProperties = (props) => {
|
|
|
16068
16738
|
const { material, selectionService } = props;
|
|
16069
16739
|
const scene = material.getScene();
|
|
16070
16740
|
const selectEntity = (entity) => (selectionService.selectedEntity = entity);
|
|
16071
|
-
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component:
|
|
16741
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Diffuse", target: material, propertyKey: "diffuseTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Specular", target: material, propertyKey: "specularTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, uniqueId: "StandardMaterialTextures_Reflection", label: "Reflection", target: material, propertyKey: "reflectionTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Refraction", target: material, propertyKey: "refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Emissive", target: material, propertyKey: "emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Bump", target: material, propertyKey: "bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Opacity", target: material, propertyKey: "opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Ambient", target: material, propertyKey: "ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Lightmap", target: material, propertyKey: "lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: MaterialTextureDebugPropertyLine, label: "Detailmap", target: material.detailMap, propertyKey: "texture", propertyPath: "detailMap.texture", scene: scene, onLink: selectEntity, defaultValue: null, material: material }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Lightmap as Shadowmap", target: material, propertyKey: "useLightmapAsShadowmap" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Detailmap", target: material.detailMap, propertyKey: "isEnabled", propertyPath: "detailMap.isEnabled" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Decalmap", target: material.decalMap, propertyKey: "isEnabled", propertyPath: "decalMap.isEnabled" })] }));
|
|
16072
16742
|
};
|
|
16073
16743
|
/**
|
|
16074
16744
|
* Displays the levels properties of a standard material.
|
|
@@ -21525,6 +22195,243 @@ const AtmosphereExplorerServiceDefinition = {
|
|
|
21525
22195
|
},
|
|
21526
22196
|
};
|
|
21527
22197
|
|
|
22198
|
+
function IsRoutable(node) {
|
|
22199
|
+
return node instanceof AbstractSoundSource || node instanceof AudioBus;
|
|
22200
|
+
}
|
|
22201
|
+
function GetEngineDisplayName(engine) {
|
|
22202
|
+
return LastCreatedAudioEngine() === engine ? "Last Created Audio Engine" : "Other Audio Engine";
|
|
22203
|
+
}
|
|
22204
|
+
const AudioV2ExplorerServiceDefinition = {
|
|
22205
|
+
friendlyName: "Audio V2 Explorer",
|
|
22206
|
+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity, GizmoServiceIdentity, SelectionServiceIdentity],
|
|
22207
|
+
factory: (sceneExplorerService, sceneContext, gizmoService, selectionService) => {
|
|
22208
|
+
// Section-level observables driven by per-engine subscriptions below.
|
|
22209
|
+
const entityAddedObservable = new Observable();
|
|
22210
|
+
const entityRemovedObservable = new Observable();
|
|
22211
|
+
const entityMovedObservable = new Observable();
|
|
22212
|
+
// Notified whenever any engine's "Last Created" status may have changed (i.e. an engine
|
|
22213
|
+
// was added or removed). Display info hooks subscribe to this to refresh the engine label.
|
|
22214
|
+
const engineDisplayNameChangedObservable = new Observable();
|
|
22215
|
+
// Per-engine subscription tokens (disposed when the engine is disposed).
|
|
22216
|
+
const engineSubscriptions = new Map();
|
|
22217
|
+
// Per-instance outBus interception tokens for sounds / sound sources / audio buses.
|
|
22218
|
+
const outBusInterceptors = new Map();
|
|
22219
|
+
const subscribeOutBus = (entity) => {
|
|
22220
|
+
if (outBusInterceptors.has(entity)) {
|
|
22221
|
+
return;
|
|
22222
|
+
}
|
|
22223
|
+
outBusInterceptors.set(entity, InterceptProperty(entity, "outBus", {
|
|
22224
|
+
afterSet: () => entityMovedObservable.notifyObservers(entity),
|
|
22225
|
+
}));
|
|
22226
|
+
};
|
|
22227
|
+
const unsubscribeOutBus = (entity) => {
|
|
22228
|
+
outBusInterceptors.get(entity)?.dispose();
|
|
22229
|
+
outBusInterceptors.delete(entity);
|
|
22230
|
+
};
|
|
22231
|
+
const subscribeEngine = (engine) => {
|
|
22232
|
+
if (engineSubscriptions.has(engine)) {
|
|
22233
|
+
return;
|
|
22234
|
+
}
|
|
22235
|
+
const nodeAddedObserver = engine.onNodeAddedObservable.add((node) => {
|
|
22236
|
+
if (IsRoutable(node)) {
|
|
22237
|
+
subscribeOutBus(node);
|
|
22238
|
+
}
|
|
22239
|
+
entityAddedObservable.notifyObservers(node);
|
|
22240
|
+
});
|
|
22241
|
+
const nodeRemovedObserver = engine.onNodeRemovedObservable.add((node) => {
|
|
22242
|
+
if (IsRoutable(node)) {
|
|
22243
|
+
unsubscribeOutBus(node);
|
|
22244
|
+
}
|
|
22245
|
+
entityRemovedObservable.notifyObservers(node);
|
|
22246
|
+
});
|
|
22247
|
+
const disposeObserver = engine.onDisposeObservable.add(() => {
|
|
22248
|
+
unsubscribeEngine(engine);
|
|
22249
|
+
entityRemovedObservable.notifyObservers(engine);
|
|
22250
|
+
engineDisplayNameChangedObservable.notifyObservers();
|
|
22251
|
+
});
|
|
22252
|
+
// Seed outBus interception for nodes that already exist on this engine.
|
|
22253
|
+
for (const node of engine.nodes) {
|
|
22254
|
+
if (IsRoutable(node)) {
|
|
22255
|
+
subscribeOutBus(node);
|
|
22256
|
+
}
|
|
22257
|
+
}
|
|
22258
|
+
engineSubscriptions.set(engine, {
|
|
22259
|
+
dispose: () => {
|
|
22260
|
+
nodeAddedObserver.remove();
|
|
22261
|
+
nodeRemovedObserver.remove();
|
|
22262
|
+
disposeObserver.remove();
|
|
22263
|
+
},
|
|
22264
|
+
});
|
|
22265
|
+
};
|
|
22266
|
+
const unsubscribeEngine = (engine) => {
|
|
22267
|
+
engineSubscriptions.get(engine)?.dispose();
|
|
22268
|
+
engineSubscriptions.delete(engine);
|
|
22269
|
+
};
|
|
22270
|
+
// Seed with engines that already exist.
|
|
22271
|
+
for (const engine of AudioEngineV2.Instances) {
|
|
22272
|
+
subscribeEngine(engine);
|
|
22273
|
+
}
|
|
22274
|
+
// React to new engines.
|
|
22275
|
+
const engineCreatedObserver = OnAudioEngineV2CreatedObservable.add((engine) => {
|
|
22276
|
+
subscribeEngine(engine);
|
|
22277
|
+
entityAddedObservable.notifyObservers(engine);
|
|
22278
|
+
engineDisplayNameChangedObservable.notifyObservers();
|
|
22279
|
+
});
|
|
22280
|
+
const sectionRegistration = sceneExplorerService.addSection({
|
|
22281
|
+
displayName: "Audio V2",
|
|
22282
|
+
order: 1500 /* DefaultSectionsOrder.AudioV2 */,
|
|
22283
|
+
getRootEntities: () => [...AudioEngineV2.Instances],
|
|
22284
|
+
getEntityChildren: (entity) => {
|
|
22285
|
+
if (entity instanceof AudioEngineV2) {
|
|
22286
|
+
const children = [];
|
|
22287
|
+
for (const node of entity.nodes) {
|
|
22288
|
+
if (node instanceof MainAudioBus) {
|
|
22289
|
+
children.push(node);
|
|
22290
|
+
}
|
|
22291
|
+
else if (IsRoutable(node) && !node.outBus) {
|
|
22292
|
+
// Surface routable nodes that don't route through a bus (e.g. microphone
|
|
22293
|
+
// sound sources, or sounds with outBus explicitly cleared) directly under
|
|
22294
|
+
// the engine so they remain visible in the tree.
|
|
22295
|
+
children.push(node);
|
|
22296
|
+
}
|
|
22297
|
+
}
|
|
22298
|
+
return children;
|
|
22299
|
+
}
|
|
22300
|
+
if (entity instanceof MainAudioBus || entity instanceof AudioBus) {
|
|
22301
|
+
const children = [];
|
|
22302
|
+
for (const node of entity.engine.nodes) {
|
|
22303
|
+
if (IsRoutable(node) && node.outBus === entity) {
|
|
22304
|
+
children.push(node);
|
|
22305
|
+
}
|
|
22306
|
+
}
|
|
22307
|
+
return children;
|
|
22308
|
+
}
|
|
22309
|
+
return [];
|
|
22310
|
+
},
|
|
22311
|
+
getEntityDisplayInfo: (entity) => {
|
|
22312
|
+
const onChangeObservable = new Observable();
|
|
22313
|
+
let nodeNameObserver = null;
|
|
22314
|
+
let engineDisplayObserver = null;
|
|
22315
|
+
if (entity instanceof AudioEngineV2) {
|
|
22316
|
+
engineDisplayObserver = engineDisplayNameChangedObservable.add(() => onChangeObservable.notifyObservers());
|
|
22317
|
+
}
|
|
22318
|
+
else {
|
|
22319
|
+
nodeNameObserver = entity.onNameChangedObservable.add(() => onChangeObservable.notifyObservers());
|
|
22320
|
+
}
|
|
22321
|
+
return {
|
|
22322
|
+
get name() {
|
|
22323
|
+
if (entity instanceof AudioEngineV2) {
|
|
22324
|
+
return GetEngineDisplayName(entity);
|
|
22325
|
+
}
|
|
22326
|
+
return entity.name || `Unnamed ${entity.getClassName()}`;
|
|
22327
|
+
},
|
|
22328
|
+
onChange: onChangeObservable,
|
|
22329
|
+
dispose: () => {
|
|
22330
|
+
nodeNameObserver?.remove();
|
|
22331
|
+
engineDisplayObserver?.remove();
|
|
22332
|
+
onChangeObservable.clear();
|
|
22333
|
+
},
|
|
22334
|
+
};
|
|
22335
|
+
},
|
|
22336
|
+
entityIcon: ({ entity }) => {
|
|
22337
|
+
const color = tokens.colorPaletteForestForeground2;
|
|
22338
|
+
if (entity instanceof AudioEngineV2) {
|
|
22339
|
+
return jsx(HeadphonesSoundWaveRegular, { color: color });
|
|
22340
|
+
}
|
|
22341
|
+
if (entity instanceof AbstractAudioBus) {
|
|
22342
|
+
return jsx(ArrowEnterUpRegular, { color: color });
|
|
22343
|
+
}
|
|
22344
|
+
if (entity instanceof StaticSound) {
|
|
22345
|
+
return jsx(SoundWaveCircleRegular, { color: color });
|
|
22346
|
+
}
|
|
22347
|
+
if (entity instanceof StreamingSound) {
|
|
22348
|
+
return jsx(SoundWaveCircleFilled, { color: color });
|
|
22349
|
+
}
|
|
22350
|
+
if (entity instanceof AbstractSoundSource) {
|
|
22351
|
+
return jsx(CatchUpRegular, { color: color });
|
|
22352
|
+
}
|
|
22353
|
+
return jsx(Fragment, {});
|
|
22354
|
+
},
|
|
22355
|
+
getEntityAddedObservables: () => [entityAddedObservable],
|
|
22356
|
+
getEntityRemovedObservables: () => [entityRemovedObservable],
|
|
22357
|
+
getEntityMovedObservables: () => [entityMovedObservable],
|
|
22358
|
+
});
|
|
22359
|
+
// Spatial-audio visualization gizmo toggle.
|
|
22360
|
+
const spatialGizmoCommandRegistration = sceneExplorerService.addEntityCommand({
|
|
22361
|
+
predicate: (entity) => entity instanceof AbstractSoundSource && entity._isSpatial,
|
|
22362
|
+
order: 800 /* DefaultCommandsOrder.GizmoActive */,
|
|
22363
|
+
getCommand: (source) => {
|
|
22364
|
+
const onChangeObservable = new Observable();
|
|
22365
|
+
let gizmoRef = null;
|
|
22366
|
+
let onClickedObserver = null;
|
|
22367
|
+
const releaseGizmo = () => {
|
|
22368
|
+
onClickedObserver?.dispose();
|
|
22369
|
+
onClickedObserver = null;
|
|
22370
|
+
gizmoRef?.dispose();
|
|
22371
|
+
gizmoRef = null;
|
|
22372
|
+
};
|
|
22373
|
+
return {
|
|
22374
|
+
type: "toggle",
|
|
22375
|
+
get displayName() {
|
|
22376
|
+
return `Turn ${gizmoRef ? "Off" : "On"} Gizmo`;
|
|
22377
|
+
},
|
|
22378
|
+
icon: () => (gizmoRef ? jsx(EyeRegular, {}) : jsx(EyeOffRegular, {})),
|
|
22379
|
+
get isEnabled() {
|
|
22380
|
+
return !!gizmoRef;
|
|
22381
|
+
},
|
|
22382
|
+
set isEnabled(enabled) {
|
|
22383
|
+
if (enabled) {
|
|
22384
|
+
if (!gizmoRef) {
|
|
22385
|
+
const scene = sceneContext.currentScene;
|
|
22386
|
+
if (scene) {
|
|
22387
|
+
const ref = gizmoService.getSpatialAudioGizmo(source, scene);
|
|
22388
|
+
gizmoRef = ref;
|
|
22389
|
+
// Clicking the gizmo in the viewport selects the underlying sound source
|
|
22390
|
+
// so the inspector navigates to it (mirrors how camera/light gizmos behave
|
|
22391
|
+
// via the scene picking path).
|
|
22392
|
+
const observer = ref.value.onClickedObservable.add((clickedSource) => {
|
|
22393
|
+
selectionService.selectedEntity = clickedSource;
|
|
22394
|
+
});
|
|
22395
|
+
onClickedObserver = { dispose: () => observer.remove() };
|
|
22396
|
+
onChangeObservable.notifyObservers();
|
|
22397
|
+
}
|
|
22398
|
+
}
|
|
22399
|
+
}
|
|
22400
|
+
else if (gizmoRef) {
|
|
22401
|
+
releaseGizmo();
|
|
22402
|
+
onChangeObservable.notifyObservers();
|
|
22403
|
+
}
|
|
22404
|
+
},
|
|
22405
|
+
onChange: onChangeObservable,
|
|
22406
|
+
dispose: () => {
|
|
22407
|
+
releaseGizmo();
|
|
22408
|
+
onChangeObservable.clear();
|
|
22409
|
+
},
|
|
22410
|
+
};
|
|
22411
|
+
},
|
|
22412
|
+
});
|
|
22413
|
+
return {
|
|
22414
|
+
dispose: () => {
|
|
22415
|
+
engineCreatedObserver.remove();
|
|
22416
|
+
for (const subscription of engineSubscriptions.values()) {
|
|
22417
|
+
subscription.dispose();
|
|
22418
|
+
}
|
|
22419
|
+
engineSubscriptions.clear();
|
|
22420
|
+
for (const token of outBusInterceptors.values()) {
|
|
22421
|
+
token.dispose();
|
|
22422
|
+
}
|
|
22423
|
+
outBusInterceptors.clear();
|
|
22424
|
+
entityAddedObservable.clear();
|
|
22425
|
+
entityRemovedObservable.clear();
|
|
22426
|
+
entityMovedObservable.clear();
|
|
22427
|
+
engineDisplayNameChangedObservable.clear();
|
|
22428
|
+
spatialGizmoCommandRegistration.dispose();
|
|
22429
|
+
sectionRegistration.dispose();
|
|
22430
|
+
},
|
|
22431
|
+
};
|
|
22432
|
+
},
|
|
22433
|
+
};
|
|
22434
|
+
|
|
21528
22435
|
const DisposableCommandServiceDefinition = {
|
|
21529
22436
|
friendlyName: "Disposable Command Service",
|
|
21530
22437
|
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
|
|
@@ -25288,7 +26195,7 @@ const Dialog = (props) => {
|
|
|
25288
26195
|
if (!data.open && onDismiss) {
|
|
25289
26196
|
onDismiss();
|
|
25290
26197
|
}
|
|
25291
|
-
}, children: jsx(DialogSurface, { children: jsxs(DialogBody, { children: [jsx(DialogTitle, { action: onDismiss ? (jsx(DialogTrigger, { action: "close", children: jsx(Button, { appearance: "subtle",
|
|
26198
|
+
}, children: jsx(DialogSurface, { children: jsxs(DialogBody, { children: [jsx(DialogTitle, { action: onDismiss ? (jsx(DialogTrigger, { action: "close", children: jsx(Button, { appearance: "subtle", ariaLabel: "close", icon: DismissRegular }) })) : undefined, children: title }), jsx(DialogContent, { children: children }), actions && actions.length > 0 && (jsx(DialogActions, { children: actions.map((action, index) => (jsx(Button, { appearance: action.appearance ?? "secondary", onClick: action.onClick, label: action.label }, index))) }))] }) }) }));
|
|
25292
26199
|
};
|
|
25293
26200
|
|
|
25294
26201
|
const SmartAssetsPaneKey = "Smart Assets";
|
|
@@ -25570,7 +26477,7 @@ function ShowInspector(scene, options = {}) {
|
|
|
25570
26477
|
// Helps with managing gizmos and a shared utility layer.
|
|
25571
26478
|
GizmoServiceDefinition,
|
|
25572
26479
|
// Scene explorer tab and related services.
|
|
25573
|
-
SceneExplorerServiceDefinition, NodeExplorerServiceDefinition, SkeletonExplorerServiceDefinition, MaterialExplorerServiceDefinition, TextureExplorerServiceDefinition, PostProcessExplorerServiceDefinition, RenderingPipelineExplorerServiceDefinition, EffectLayerExplorerServiceDefinition, ParticleSystemExplorerServiceDefinition, SpriteManagerExplorerServiceDefinition, AnimationGroupExplorerServiceDefinition, GuiExplorerServiceDefinition, FrameGraphExplorerServiceDefinition, AtmosphereExplorerServiceDefinition, SoundExplorerServiceDefinition, DisposableCommandServiceDefinition,
|
|
26480
|
+
SceneExplorerServiceDefinition, NodeExplorerServiceDefinition, SkeletonExplorerServiceDefinition, MaterialExplorerServiceDefinition, TextureExplorerServiceDefinition, PostProcessExplorerServiceDefinition, RenderingPipelineExplorerServiceDefinition, EffectLayerExplorerServiceDefinition, ParticleSystemExplorerServiceDefinition, SpriteManagerExplorerServiceDefinition, AnimationGroupExplorerServiceDefinition, GuiExplorerServiceDefinition, FrameGraphExplorerServiceDefinition, AtmosphereExplorerServiceDefinition, SoundExplorerServiceDefinition, AudioV2ExplorerServiceDefinition, DisposableCommandServiceDefinition,
|
|
25574
26481
|
// Properties pane tab and related services.
|
|
25575
26482
|
ScenePropertiesServiceDefinition, PropertiesServiceDefinition, TexturePropertiesServiceDefinition, CommonPropertiesServiceDefinition, TransformPropertiesServiceDefinition, AnimationPropertiesServiceDefinition, NodePropertiesServiceDefinition, PhysicsPropertiesServiceDefinition, SkeletonPropertiesServiceDefinition, MaterialPropertiesServiceDefinition, LightPropertiesServiceDefinition, SpritePropertiesServiceDefinition, ParticleSystemPropertiesServiceDefinition, CameraPropertiesServiceDefinition, PostProcessPropertiesServiceDefinition, RenderingPipelinePropertiesServiceDefinition, EffectLayerPropertiesServiceDefinition, FrameGraphPropertiesServiceDefinition, AnimationGroupPropertiesServiceDefinition, MetadataPropertiesServiceDefinition, AtmospherePropertiesServiceDefinition, AudioPropertiesServiceDefinition,
|
|
25576
26483
|
// Texture editor and related services.
|
|
@@ -26442,4 +27349,4 @@ const TextAreaPropertyLine = (props) => {
|
|
|
26442
27349
|
AttachDebugLayer();
|
|
26443
27350
|
|
|
26444
27351
|
export { GetPropertyDescriptor as $, Accordion as A, Button as B, CheckboxPropertyLine as C, Color4PropertyLine as D, ColorPickerPopup as E, ColorStepGradientComponent as F, ComboBox as G, ComboBoxPropertyLine as H, ConstructorFactory as I, ConvertOptions as J, DebugServiceIdentity as K, Link as L, MessageBar as M, NumberInputPropertyLine as N, DetachDebugLayer as O, Popover as P, DraggableLine as Q, Dropdown as R, ShellServiceIdentity as S, TextInputPropertyLine as T, EntitySelector as U, Vector3PropertyLine as V, ErrorBoundary as W, ExtensibleAccordion as X, FactorGradientComponent as Y, FactorGradientList as Z, FileUploadLine as _, useToast as a, ThemeServiceIdentity as a$, GizmoServiceIdentity as a0, HexPropertyLine as a1, InfoLabel as a2, InputHexField as a3, InputHsvField as a4, Inspector as a5, InterceptFunction as a6, InterceptProperty as a7, IsPropertyReadonly as a8, LineContainer as a9, SearchBox as aA, SelectionServiceDefinition as aB, SettingsServiceIdentity as aC, SettingsStore as aD, SettingsStoreIdentity as aE, ShowInspector as aF, SidePaneContainer as aG, SkeletonSelector as aH, Slider as aI, SpinButton as aJ, StartInspectable as aK, StatsServiceIdentity as aL, StringDropdown as aM, StringDropdownPropertyLine as aN, StringifiedPropertyLine as aO, Switch as aP, SwitchPropertyLine as aQ, SyncedSliderInput as aR, SyncedSliderPropertyLine as aS, TeachingMoment as aT, TextAreaPropertyLine as aU, TextInput as aV, TextPropertyLine as aW, Textarea as aX, TextureSelector as aY, TextureUpload as aZ, Theme as a_, LinkPropertyLine as aa, LinkToEntityPropertyLine as ab, List as ac, MakeDialogTeachingMoment as ad, MakeLazyComponent as ae, MakeModularBridge as af, MakeModularTool as ag, MakePopoverTeachingMoment as ah, MakePropertyHook as ai, MakeTeachingMoment as aj, MaterialSelector as ak, NodeSelector as al, NumberDropdown as am, NumberDropdownPropertyLine as an, ObservableCollection as ao, Pane as ap, PlaceholderPropertyLine as aq, PositionedPopover as ar, PropertiesServiceIdentity as as, Property as at, PropertyContext as au, PropertyLine as av, QuaternionPropertyLine as aw, RotationVectorPropertyLine as ax, SceneExplorerServiceIdentity as ay, SearchBar as az, useInterceptObservable as b, ToastProvider as b0, ToggleButton as b1, Tooltip as b2, UploadButton as b3, Vector2PropertyLine as b4, Vector4PropertyLine as b5, WatcherServiceIdentity as b6, inspectorAssetNotFoundHandler as b7, useAngleConverters as b8, useAsyncResource as b9, useColor3Property as ba, useColor4Property as bb, useEventListener as bc, useEventfulState as bd, useKeyListener as be, useKeyState as bf, useObservableCollection as bg, useOrderedObservableCollection as bh, usePollingObservable as bi, usePropertyChangedNotifier as bj, useQuaternionProperty as bk, useResource as bl, useTheme as bm, useThemeMode as bn, useVector3Property as bo, LinkToEntity as c, SpinButtonPropertyLine as d, useProperty as e, SceneContextIdentity as f, SelectionServiceIdentity as g, useObservableState as h, AccordionSection as i, ButtonLine as j, ToolsServiceIdentity as k, AccordionSectionItem as l, AttachDebugLayer as m, BooleanBadgePropertyLine as n, BoundProperty as o, BridgeCommandRegistryIdentity as p, BuiltInsExtensionFeed as q, Checkbox as r, ChildWindow as s, Collapse as t, useExtensionManager as u, Color3GradientComponent as v, Color3GradientList as w, Color3PropertyLine as x, Color4GradientComponent as y, Color4GradientList as z };
|
|
26445
|
-
//# sourceMappingURL=index
|
|
27352
|
+
//# sourceMappingURL=index--oJsOVVX.js.map
|