@babylonjs/inspector 8.30.3-preview → 8.30.4-preview

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/index.js CHANGED
@@ -3,7 +3,7 @@ import { useMemo, useEffect, useState, useRef, useCallback, forwardRef, createCo
3
3
  import { Color3, Color4 } from '@babylonjs/core/Maths/math.color.js';
4
4
  import { Vector3, Quaternion, Matrix, Vector2, Vector4, TmpVectors } from '@babylonjs/core/Maths/math.vector.js';
5
5
  import { Observable } from '@babylonjs/core/Misc/observable.js';
6
- import { makeStyles, ToggleButton as ToggleButton$1, Button as Button$1, tokens, Link, InfoLabel as InfoLabel$1, Body1Stronger, Checkbox as Checkbox$1, Body1, Accordion as Accordion$1, AccordionItem, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, mergeClasses, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Body1Strong, TabList, Tooltip, Title3, Tab, SearchBox as SearchBox$1, FlatTree, FlatTreeItem, TreeItemLayout, Menu, MenuTrigger, MenuPopover, MenuList, MenuItem, Switch as Switch$1, PresenceBadge, Spinner, Dialog, DialogTrigger, DialogSurface, DialogBody, DialogTitle, DialogContent, SplitButton, MenuItemRadio, createLightTheme, createDarkTheme, FluentProvider, DialogActions, List as List$1, ListItem, useId, Input, SpinButton as SpinButton$1, Slider, MessageBar as MessageBar$1, MessageBarBody, MessageBarTitle, Badge, Popover, PopoverTrigger, ColorSwatch, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, Dropdown as Dropdown$1, Option, Textarea as Textarea$1, useComboboxFilter, Combobox, Field } from '@fluentui/react-components';
6
+ import { makeStyles, ToggleButton as ToggleButton$1, Button as Button$1, tokens, Link, InfoLabel as InfoLabel$1, Body1Stronger, Checkbox as Checkbox$1, Body1, Accordion as Accordion$1, AccordionItem, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, mergeClasses, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Body1Strong, TabList, Tooltip, Title3, Tab, SearchBox as SearchBox$1, FlatTree, FlatTreeItem, TreeItemLayout, Menu, MenuTrigger, MenuPopover, MenuList, MenuItem, Switch as Switch$1, PresenceBadge, Spinner, Dialog, DialogTrigger, DialogSurface, DialogBody, DialogTitle, DialogContent, SplitButton, MenuItemRadio, createLightTheme, createDarkTheme, FluentProvider, DialogActions, List as List$1, ListItem, useId, Input, SpinButton as SpinButton$1, Slider, MessageBar as MessageBar$1, MessageBarBody, MessageBarTitle, Badge, Dropdown as Dropdown$1, Option, Popover, PopoverTrigger, ColorSwatch, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, Textarea as Textarea$1, Toolbar as Toolbar$1, ToolbarButton, useComboboxFilter, Combobox, Field } from '@fluentui/react-components';
7
7
  export { Link } from '@fluentui/react-components';
8
8
  import { ChevronCircleRight20Regular, ChevronCircleDown20Regular, CopyRegular, PanelLeftExpandRegular, PanelLeftContractRegular, PanelRightExpandRegular, PanelRightContractRegular, DocumentTextRegular, FilterRegular, MoviesAndTvRegular, CubeTreeRegular, BugRegular, SettingsRegular, ArrowUploadRegular, DataBarHorizontalRegular, WrenchRegular, AppsAddInRegular, DismissRegular, WeatherSunnyRegular, WeatherMoonRegular, ErrorCircleRegular, ArrowMoveRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, GlobeRegular, SaveRegular, ArrowUndoRegular, ClearFormattingRegular, DeleteRegular, EyeOffFilled, EyeFilled, ArrowMoveFilled, StopFilled, PlayFilled, StackRegular, FilmstripRegular, PauseFilled, WeatherSunnyLowFilled, LayerRegular, FrameRegular, PlayRegular, AppGenericRegular, PaintBrushRegular, BoxRegular, BranchRegular, CameraRegular, LightbulbRegular, EyeRegular, EyeOffRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, Cone16Filled, Cone16Regular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, DeleteFilled } from '@fluentui/react-icons';
9
9
  import { Collapse as Collapse$1 } from '@fluentui/react-motion-components-preview';
@@ -97,6 +97,7 @@ import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture.js';
97
97
  import { MultiRenderTarget } from '@babylonjs/core/Materials/Textures/multiRenderTarget.js';
98
98
  import { RenderTargetTexture } from '@babylonjs/core/Materials/Textures/renderTargetTexture.js';
99
99
  import { ThinTexture } from '@babylonjs/core/Materials/Textures/thinTexture.js';
100
+ import { WhenTextureReadyAsync, GetTextureDataAsync } from '@babylonjs/core/Misc/textureTools.js';
100
101
  import '@babylonjs/core/PostProcesses/RenderPipeline/postProcessRenderPipelineManagerSceneComponent.js';
101
102
  import '@babylonjs/core/Sprites/spriteSceneComponent.js';
102
103
  import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture.js';
@@ -605,6 +606,7 @@ const useCollapseStyles = makeStyles({
605
606
  * @returns
606
607
  */
607
608
  const Collapse = (props) => {
609
+ Collapse.displayName = "Collapse";
608
610
  const classes = useCollapseStyles();
609
611
  return (jsx(Collapse$1, { visible: props.visible, orientation: props.orientation, children: jsx("div", { className: `${classes.collapseContent} ${props.orientation === "horizontal" ? classes.horizontal : classes.vertical}`, children: props.children }) }));
610
612
  };
@@ -640,6 +642,7 @@ const ToolContext = createContext({ useFluent: false, disableCopy: false, toolNa
640
642
  * @returns
641
643
  */
642
644
  const ToggleButton = (props) => {
645
+ ToggleButton.displayName = "ToggleButton";
643
646
  const { value, onChange, title, appearance = "subtle" } = props;
644
647
  const [checked, setChecked] = useState(value);
645
648
  const toggle = useCallback(() => {
@@ -656,6 +659,7 @@ const ToggleButton = (props) => {
656
659
  };
657
660
 
658
661
  const Button = (props) => {
662
+ Button.displayName = "Button";
659
663
  // eslint-disable-next-line @typescript-eslint/naming-convention
660
664
  const { icon: Icon, label, ...buttonProps } = props;
661
665
  return (jsx(Button$1, { iconPosition: "after", ...buttonProps, icon: Icon && jsx(Icon, {}), children: label && props.label }));
@@ -671,8 +675,15 @@ const CustomTokens = {
671
675
  };
672
676
  const UniformWidthStyling = { width: CustomTokens.inputWidth, textAlign: "right", boxSizing: "border-box" };
673
677
  const useInputStyles$1 = makeStyles({
674
- invalid: { backgroundColor: tokens.colorPaletteRedBackground2, ...UniformWidthStyling },
675
- valid: UniformWidthStyling,
678
+ input: UniformWidthStyling,
679
+ invalid: { backgroundColor: tokens.colorPaletteRedBackground2 },
680
+ container: {
681
+ flex: 1,
682
+ display: "flex",
683
+ flexDirection: "column",
684
+ justifyContent: "center", // align items vertically
685
+ gap: "4px",
686
+ },
676
687
  });
677
688
  function HandleOnBlur(event) {
678
689
  event.stopPropagation();
@@ -732,6 +743,7 @@ const usePropertyLineStyles = makeStyles({
732
743
  *
733
744
  */
734
745
  const PropertyLine = forwardRef((props, ref) => {
746
+ PropertyLine.displayName = "PropertyLine";
735
747
  const classes = usePropertyLineStyles();
736
748
  const { label, onCopy, expandedContent, children, nullable, ignoreNullable } = props;
737
749
  const [expanded, setExpanded] = useState("expandByDefault" in props ? props.expandByDefault : false);
@@ -775,6 +787,7 @@ const PlaceholderPropertyLine = (props) => {
775
787
  * @returns property-line wrapped link
776
788
  */
777
789
  const LinkPropertyLine = (props) => {
790
+ LinkPropertyLine.displayName = "LinkPropertyLine";
778
791
  return (jsx(PropertyLine, { ...props, children: jsx(Link, { inline: true, onClick: () => props.onLink?.(), href: props.url, title: props.title, children: jsx(Body1, { children: props.value }) }) }));
779
792
  };
780
793
 
@@ -793,7 +806,7 @@ const LinkToEntityPropertyLine = (props) => {
793
806
  !linkedEntity.reservedDataStore?.hidden && jsx(LinkPropertyLine, { ...rest, value: linkedEntity.name, onLink: () => (selectionService.selectedEntity = linkedEntity) }));
794
807
  };
795
808
 
796
- const useStyles$f = makeStyles({
809
+ const useStyles$g = makeStyles({
797
810
  accordion: {
798
811
  overflowX: "hidden",
799
812
  overflowY: "auto",
@@ -813,11 +826,13 @@ const useStyles$f = makeStyles({
813
826
  },
814
827
  });
815
828
  const AccordionSection = (props) => {
816
- const classes = useStyles$f();
829
+ AccordionSection.displayName = "AccordionSection";
830
+ const classes = useStyles$g();
817
831
  return jsx("div", { className: classes.panelDiv, children: props.children });
818
832
  };
819
833
  const Accordion = (props) => {
820
- const classes = useStyles$f();
834
+ Accordion.displayName = "Accordion";
835
+ const classes = useStyles$g();
821
836
  const { children, ...rest } = props;
822
837
  const validChildren = useMemo(() => {
823
838
  return (Children.map(children, (child) => {
@@ -867,7 +882,7 @@ function AsReadonlyArray(array) {
867
882
  return array;
868
883
  }
869
884
  // eslint-disable-next-line @typescript-eslint/naming-convention
870
- const useStyles$e = makeStyles({
885
+ const useStyles$f = makeStyles({
871
886
  rootDiv: {
872
887
  flex: 1,
873
888
  overflow: "hidden",
@@ -876,7 +891,7 @@ const useStyles$e = makeStyles({
876
891
  },
877
892
  });
878
893
  function ExtensibleAccordion(props) {
879
- const classes = useStyles$e();
894
+ const classes = useStyles$f();
880
895
  const { children, sections, sectionContent, context } = props;
881
896
  const defaultSections = useMemo(() => {
882
897
  const defaultSections = [];
@@ -964,7 +979,7 @@ function ExtensibleAccordion(props) {
964
979
  })] })) }));
965
980
  }
966
981
 
967
- const useStyles$d = makeStyles({
982
+ const useStyles$e = makeStyles({
968
983
  paneRootDiv: {
969
984
  display: "flex",
970
985
  flex: 1,
@@ -977,12 +992,12 @@ const useStyles$d = makeStyles({
977
992
  */
978
993
  const SidePaneContainer = forwardRef((props, ref) => {
979
994
  const { className, ...rest } = props;
980
- const classes = useStyles$d();
995
+ const classes = useStyles$e();
981
996
  return (jsx("div", { className: mergeClasses(classes.paneRootDiv, className), ref: ref, ...rest, children: props.children }));
982
997
  });
983
998
 
984
999
  // eslint-disable-next-line @typescript-eslint/naming-convention
985
- const useStyles$c = makeStyles({
1000
+ const useStyles$d = makeStyles({
986
1001
  extensionTeachingPopover: {
987
1002
  maxWidth: "320px",
988
1003
  },
@@ -993,7 +1008,7 @@ const useStyles$c = makeStyles({
993
1008
  * @returns The teaching moment popover.
994
1009
  */
995
1010
  const TeachingMoment = ({ shouldDisplay, positioningRef, onOpenChange, title, description }) => {
996
- const classes = useStyles$c();
1011
+ const classes = useStyles$d();
997
1012
  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 })] }) }));
998
1013
  };
999
1014
 
@@ -1280,13 +1295,13 @@ function ConstructorFactory(constructor) {
1280
1295
  }
1281
1296
 
1282
1297
  // eslint-disable-next-line @typescript-eslint/naming-convention
1283
- const useStyles$b = makeStyles({
1298
+ const useStyles$c = makeStyles({
1284
1299
  placeholderDiv: {
1285
1300
  padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
1286
1301
  },
1287
1302
  });
1288
1303
  const PropertiesPane = (props) => {
1289
- const classes = useStyles$b();
1304
+ const classes = useStyles$c();
1290
1305
  const entity = props.context;
1291
1306
  return entity != null ? (jsx(ExtensibleAccordion, { ...props })) : (jsx("div", { className: classes.placeholderDiv, children: jsx(Body1Strong, { italic: true, children: "No entity selected." }) }));
1292
1307
  };
@@ -1329,7 +1344,7 @@ const SelectionServiceDefinition = {
1329
1344
  const RootComponentServiceIdentity = Symbol("RootComponent");
1330
1345
  const ShellServiceIdentity = Symbol("ShellService");
1331
1346
  // eslint-disable-next-line @typescript-eslint/naming-convention
1332
- const useStyles$a = makeStyles({
1347
+ const useStyles$b = makeStyles({
1333
1348
  mainView: {
1334
1349
  flex: 1,
1335
1350
  display: "flex",
@@ -1452,7 +1467,7 @@ const useStyles$a = makeStyles({
1452
1467
  });
1453
1468
  // 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.
1454
1469
  const ToolbarItem = ({ location, alignment, id, component: Component, displayName: displayName, suppressTeachingMoment }) => {
1455
- const classes = useStyles$a();
1470
+ const classes = useStyles$b();
1456
1471
  const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Bar/${location}/${alignment}/${displayName ?? id}`), [displayName, id]);
1457
1472
  const teachingMoment = useTeachingMoment(suppressTeachingMoment);
1458
1473
  return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay && !suppressTeachingMoment, title: displayName ?? "Extension", description: `The "${displayName ?? id}" extension can be accessed here.` }), jsx("div", { className: classes.barItem, ref: teachingMoment.targetRef, children: jsx(Component, {}) })] }));
@@ -1460,7 +1475,7 @@ const ToolbarItem = ({ location, alignment, id, component: Component, displayNam
1460
1475
  // TODO: Handle overflow, possibly via https://react.fluentui.dev/?path=/docs/components-overflow--docs with priority.
1461
1476
  // This component just renders a toolbar with left aligned toolbar items on the left and right aligned toolbar items on the right.
1462
1477
  const Toolbar = ({ location, components }) => {
1463
- const classes = useStyles$a();
1478
+ const classes = useStyles$b();
1464
1479
  const leftComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "left"), [components]);
1465
1480
  const rightComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "right"), [components]);
1466
1481
  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, { location: location, alignment: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) }), jsx("div", { className: classes.barRight, children: rightComponents.map((entry) => (jsx(ToolbarItem, { location: location, alignment: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) })] })) }));
@@ -1469,7 +1484,7 @@ const Toolbar = ({ location, components }) => {
1469
1484
  const SidePaneTab = ({ alignment, id,
1470
1485
  // eslint-disable-next-line @typescript-eslint/naming-convention
1471
1486
  icon: Icon, title, suppressTeachingMoment, }) => {
1472
- const classes = useStyles$a();
1487
+ const classes = useStyles$b();
1473
1488
  const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Pane/${alignment}/${title ?? id}`), [title, id]);
1474
1489
  const teachingMoment = useTeachingMoment(suppressTeachingMoment);
1475
1490
  return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay && !suppressTeachingMoment, title: title ?? "Extension", description: `The "${title ?? id}" extension can be accessed here.` }), jsx(Tab, { ref: teachingMoment.targetRef, className: classes.tab, value: id, icon: jsx(Tooltip, { content: title ?? id, relationship: "description", children: jsx(Icon, {}) }) }, id)] }));
@@ -1478,7 +1493,7 @@ icon: Icon, title, suppressTeachingMoment, }) => {
1478
1493
  // In "compact" mode, the tab list is integrated into the pane itself.
1479
1494
  // In "full" mode, the returned tab list is later injected into the toolbar.
1480
1495
  function usePane(alignment, defaultWidth, minWidth, topPanes, bottomPanes, toolbarMode, topBarItems, bottomBarItems) {
1481
- const classes = useStyles$a();
1496
+ const classes = useStyles$b();
1482
1497
  const [topSelectedTab, setTopSelectedTab] = useState();
1483
1498
  const [bottomSelectedTab, setBottomSelectedTab] = useState();
1484
1499
  const [collapsed, setCollapsed] = useState(false);
@@ -1590,7 +1605,7 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
1590
1605
  const bottomRightPaneCollection = new ObservableCollection();
1591
1606
  const centralContentCollection = new ObservableCollection();
1592
1607
  const rootComponent = () => {
1593
- const classes = useStyles$a();
1608
+ const classes = useStyles$b();
1594
1609
  const topBarItems = useOrderedObservableCollection(topBarItemCollection);
1595
1610
  const bottomBarItems = useOrderedObservableCollection(bottomBarItemCollection);
1596
1611
  const topLeftPanes = useOrderedObservableCollection(topLeftPaneCollection);
@@ -1824,7 +1839,7 @@ function ExpandOrCollapseAll(treeItem, open, openItems) {
1824
1839
  TraverseGraph([treeItem], (treeItem) => treeItem.children, (treeItem) => addOrRemove(treeItem.type === "entity" ? treeItem.entity.uniqueId : treeItem.sectionName));
1825
1840
  }
1826
1841
  // eslint-disable-next-line @typescript-eslint/naming-convention
1827
- const useStyles$9 = makeStyles({
1842
+ const useStyles$a = makeStyles({
1828
1843
  rootDiv: {
1829
1844
  flex: 1,
1830
1845
  overflow: "hidden",
@@ -1859,7 +1874,7 @@ const ToggleCommand = (props) => {
1859
1874
  };
1860
1875
  const SceneTreeItem = (props) => {
1861
1876
  const { isSelected, select } = props;
1862
- const classes = useStyles$9();
1877
+ const classes = useStyles$a();
1863
1878
  return (jsx(FlatTreeItem, { value: "scene", itemType: "leaf", parentValue: undefined, "aria-level": 1, "aria-setsize": 1, "aria-posinset": 1, onClick: select, children: jsx(TreeItemLayout, { iconBefore: jsx(MoviesAndTvRegular, {}), className: classes.sceneTreeItemLayout, style: isSelected ? { backgroundColor: tokens.colorNeutralBackground1Selected } : undefined, children: jsx(Body1Strong, { wrap: false, truncate: true, children: "Scene" }) }) }, "scene"));
1864
1879
  };
1865
1880
  const SectionTreeItem = (props) => {
@@ -1920,7 +1935,7 @@ const EntityTreeItem = (props) => {
1920
1935
  }, children: jsx(Body1, { wrap: false, truncate: true, children: name.substring(0, 100) }) }) }, entityItem.entity.uniqueId) }), jsx(MenuPopover, { hidden: !entityItem.children?.length, children: jsxs(MenuList, { children: [jsx(MenuItem, { onClick: expandAll, children: jsx(Body1, { children: "Expand All" }) }), jsx(MenuItem, { onClick: collapseAll, children: jsx(Body1, { children: "Collapse All" }) })] }) })] }));
1921
1936
  };
1922
1937
  const SceneExplorer = (props) => {
1923
- const classes = useStyles$9();
1938
+ const classes = useStyles$a();
1924
1939
  const { sections, commandProviders, scene, selectedEntity } = props;
1925
1940
  const [openItems, setOpenItems] = useState(new Set());
1926
1941
  const [sceneVersion, setSceneVersion] = useState(0);
@@ -2210,6 +2225,7 @@ const useSwitchStyles = makeStyles({
2210
2225
  * @returns Switch component
2211
2226
  */
2212
2227
  const Switch = (props) => {
2228
+ Switch.displayName = "Switch";
2213
2229
  const classes = useSwitchStyles();
2214
2230
  const [checked, setChecked] = useState(() => props.value ?? false);
2215
2231
  useEffect(() => {
@@ -2230,6 +2246,7 @@ const Switch = (props) => {
2230
2246
  * @returns A React element representing the property line with a switch
2231
2247
  */
2232
2248
  const SwitchPropertyLine = (props) => {
2249
+ SwitchPropertyLine.displayName = "SwitchPropertyLine";
2233
2250
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2234
2251
  const { label, ...switchProps } = props;
2235
2252
  // Ensure the label gets passed to the PropertyLine component and not to the underlying switch
@@ -2464,6 +2481,7 @@ const SettingsServiceDefinition = {
2464
2481
  * @returns
2465
2482
  */
2466
2483
  const StringifiedPropertyLine = (props) => {
2484
+ StringifiedPropertyLine.displayName = "StringifiedPropertyLine";
2467
2485
  const value = props.precision !== undefined ? props.value.toFixed(props.precision) : props.value.toLocaleString();
2468
2486
  const withUnits = props.units ? `${value} ${props.units}` : value;
2469
2487
  return (jsx(PropertyLine, { ...props, children: jsx(Body1, { title: props.title, children: withUnits }) }));
@@ -2529,10 +2547,12 @@ const FrameStepsStats = ({ context: scene }) => {
2529
2547
  * @returns A button inside a line
2530
2548
  */
2531
2549
  const ButtonLine = (props) => {
2550
+ ButtonLine.displayName = "ButtonLine";
2532
2551
  return (jsx(LineContainer, { children: jsx(Button, { ...props }) }));
2533
2552
  };
2534
2553
 
2535
2554
  const FileUploadLine = (props) => {
2555
+ FileUploadLine.displayName = "FileUploadLine";
2536
2556
  const inputRef = useRef(null);
2537
2557
  const handleButtonClick = () => {
2538
2558
  inputRef.current?.click();
@@ -2655,18 +2675,19 @@ const PerformanceStats = ({ context: scene }) => {
2655
2675
  * @returns property-line wrapped text
2656
2676
  */
2657
2677
  const TextPropertyLine = (props) => {
2678
+ TextPropertyLine.displayName = "TextPropertyLine";
2658
2679
  const { value, title } = props;
2659
2680
  return (jsx(PropertyLine, { ...props, children: jsx(Body1, { title: title, children: value }) }));
2660
2681
  };
2661
2682
 
2662
- const useStyles$8 = makeStyles({
2683
+ const useStyles$9 = makeStyles({
2663
2684
  pinnedStatsPane: {
2664
2685
  flex: "0 1 auto",
2665
2686
  paddingBottom: tokens.spacingHorizontalM,
2666
2687
  },
2667
2688
  });
2668
2689
  const StatsPane = (props) => {
2669
- const classes = useStyles$8();
2690
+ const classes = useStyles$9();
2670
2691
  const scene = props.context;
2671
2692
  const engine = scene.getEngine();
2672
2693
  const fps = useObservableState(() => Math.round(engine.getFps()), engine.onBeginFrameObservable);
@@ -2678,7 +2699,10 @@ const StatsPane = (props) => {
2678
2699
  * @param props - The properties for the PropertyLine, including the boolean value to display.
2679
2700
  * @returns A PropertyLine component with a PresenceBadge indicating the boolean state.
2680
2701
  */
2681
- const BooleanBadgePropertyLine = (props) => (jsx(PropertyLine, { ...props, children: jsx(PresenceBadge, { status: props.value ? "available" : "do-not-disturb", outOfOffice: true }) }));
2702
+ const BooleanBadgePropertyLine = (props) => {
2703
+ BooleanBadgePropertyLine.displayName = "BooleanBadgePropertyLine";
2704
+ return (jsx(PropertyLine, { ...props, children: jsx(PresenceBadge, { status: props.value ? "available" : "do-not-disturb", outOfOffice: true }) }));
2705
+ };
2682
2706
 
2683
2707
  const SystemStats = ({ context: scene }) => {
2684
2708
  const engine = scene.getEngine();
@@ -2834,19 +2858,19 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
2834
2858
  name: "Export Tools",
2835
2859
  description: "Adds new features to enable exporting Babylon assets such as .gltf, .glb, .babylon, and more.",
2836
2860
  keywords: ["export", "gltf", "glb", "babylon", "exporter", "tools"],
2837
- getExtensionModuleAsync: async () => await import('./exportService-DEj9QNTe.js'),
2861
+ getExtensionModuleAsync: async () => await import('./exportService-nwkeBa_W.js'),
2838
2862
  },
2839
2863
  {
2840
2864
  name: "Capture Tools",
2841
2865
  description: "Adds new features to enable capturing screenshots, GIFs, videos, and more.",
2842
2866
  keywords: ["capture", "screenshot", "gif", "video", "tools"],
2843
- getExtensionModuleAsync: async () => await import('./captureService-BaLg4gki.js'),
2867
+ getExtensionModuleAsync: async () => await import('./captureService-Br4kaEaT.js'),
2844
2868
  },
2845
2869
  {
2846
2870
  name: "Import Tools",
2847
2871
  description: "Adds new features related to importing Babylon assets.",
2848
2872
  keywords: ["import", "tools"],
2849
- getExtensionModuleAsync: async () => await import('./importService-BoR1TPvc.js'),
2873
+ getExtensionModuleAsync: async () => await import('./importService-DtPZclnY.js'),
2850
2874
  },
2851
2875
  ]);
2852
2876
 
@@ -3288,7 +3312,7 @@ class ServiceContainer {
3288
3312
  }
3289
3313
 
3290
3314
  // eslint-disable-next-line @typescript-eslint/naming-convention
3291
- const useStyles$7 = makeStyles({
3315
+ const useStyles$8 = makeStyles({
3292
3316
  extensionButton: {},
3293
3317
  extensionsDialogSurface: {
3294
3318
  height: "auto",
@@ -3333,7 +3357,7 @@ const useStyles$7 = makeStyles({
3333
3357
  // eslint-disable-next-line @typescript-eslint/naming-convention
3334
3358
  const useTeachingMoment = MakePopoverTeachingMoment("Extensions");
3335
3359
  const ExtensionDetails = memo((props) => {
3336
- const classes = useStyles$7();
3360
+ const classes = useStyles$8();
3337
3361
  const [canInstall, setCanInstall] = useState(false);
3338
3362
  const [canUninstall, setCanUninstall] = useState(false);
3339
3363
  const [isStateChanging, setIsStateChanging] = useState(false);
@@ -3377,7 +3401,7 @@ const ExtensionListServiceDefinition = {
3377
3401
  suppressTeachingMoment: true,
3378
3402
  order: -200,
3379
3403
  component: () => {
3380
- const classes = useStyles$7();
3404
+ const classes = useStyles$8();
3381
3405
  const [selectedTab, setSelectedTab] = useState("available");
3382
3406
  const extensionManager = useExtensionManager();
3383
3407
  const [extensions, setExtensions] = useState([]);
@@ -3406,7 +3430,7 @@ const ExtensionListServiceDefinition = {
3406
3430
  },
3407
3431
  };
3408
3432
 
3409
- const useStyles$6 = makeStyles({
3433
+ const useStyles$7 = makeStyles({
3410
3434
  themeButton: {
3411
3435
  margin: `${tokens.spacingVerticalXXS} 0`,
3412
3436
  },
@@ -3425,7 +3449,7 @@ const ThemeSelectorServiceDefinition = {
3425
3449
  suppressTeachingMoment: true,
3426
3450
  order: -300,
3427
3451
  component: () => {
3428
- const classes = useStyles$6();
3452
+ const classes = useStyles$7();
3429
3453
  const { isDarkMode, themeMode, setThemeMode } = useThemeMode();
3430
3454
  const onSelectedThemeChange = useCallback((e, data) => {
3431
3455
  setThemeMode(data.checkedItems.includes("System") ? "system" : data.checkedItems[0].toLocaleLowerCase());
@@ -3471,7 +3495,7 @@ const DarkTheme = {
3471
3495
  };
3472
3496
 
3473
3497
  // eslint-disable-next-line @typescript-eslint/naming-convention
3474
- const useStyles$5 = makeStyles({
3498
+ const useStyles$6 = makeStyles({
3475
3499
  app: {
3476
3500
  colorScheme: "light dark",
3477
3501
  flexGrow: 1,
@@ -3504,7 +3528,7 @@ const useStyles$5 = makeStyles({
3504
3528
  function MakeModularTool(options) {
3505
3529
  const { containerElement, serviceDefinitions, themeMode, showThemeSelector = true, extensionFeeds = [] } = options;
3506
3530
  const modularToolRootComponent = () => {
3507
- const classes = useStyles$5();
3531
+ const classes = useStyles$6();
3508
3532
  const [extensionManagerContext, setExtensionManagerContext] = useState();
3509
3533
  const { isDarkMode } = useThemeMode(themeMode);
3510
3534
  const [requiredExtensions, setRequiredExtensions] = useState();
@@ -3704,7 +3728,7 @@ const GizmoServiceDefinition = {
3704
3728
  },
3705
3729
  };
3706
3730
 
3707
- const useStyles$4 = makeStyles({
3731
+ const useStyles$5 = makeStyles({
3708
3732
  coordinatesModeButton: {
3709
3733
  margin: `0 ${tokens.spacingVerticalXS}`,
3710
3734
  },
@@ -3714,7 +3738,7 @@ const useStyles$4 = makeStyles({
3714
3738
  });
3715
3739
  const GizmoToolbar = (props) => {
3716
3740
  const { scene, entity, gizmoService } = props;
3717
- const classes = useStyles$4();
3741
+ const classes = useStyles$5();
3718
3742
  const gizmoManager = useResource(useCallback(() => {
3719
3743
  const utilityLayerRef = gizmoService.getUtilityLayer(scene);
3720
3744
  const keepDepthUtilityLayerRef = gizmoService.getUtilityLayer(scene, "keepDepth");
@@ -3840,10 +3864,12 @@ const TargetedAnimationGeneralProperties = (props) => {
3840
3864
  * @returns
3841
3865
  */
3842
3866
  const InfoLabel = (props) => {
3867
+ InfoLabel.displayName = "InfoLabel";
3843
3868
  return (jsx(InfoLabel$1, { htmlFor: props.htmlFor, info: props.info, children: jsx(Body1, { children: props.label }) }));
3844
3869
  };
3845
3870
 
3846
3871
  const TextInput = (props) => {
3872
+ TextInput.displayName = "TextInput";
3847
3873
  const classes = useInputStyles$1();
3848
3874
  const [value, setValue] = useState(props.value);
3849
3875
  const lastCommittedValue = useRef(props.value);
@@ -3874,11 +3900,13 @@ const TextInput = (props) => {
3874
3900
  setValue(event.currentTarget.value);
3875
3901
  tryCommitValue(event.currentTarget.value);
3876
3902
  };
3903
+ const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : "", props.className);
3877
3904
  const id = useId("input-button");
3878
- return (jsxs("div", { children: [props.infoLabel && jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), jsx(Input, { ...props, id: id, size: "medium", value: value, onChange: handleChange, onKeyUp: handleKeyUp, onKeyDown: HandleKeyDown, onBlur: HandleOnBlur, className: `${!validateValue(value) ? classes.invalid : classes.valid}` })] }));
3905
+ return (jsxs("div", { className: classes.container, children: [props.infoLabel && jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), jsx(Input, { ...props, id: id, size: "medium", value: value, onChange: handleChange, onKeyUp: handleKeyUp, onKeyDown: HandleKeyDown, onBlur: HandleOnBlur, className: mergedClassName })] }));
3879
3906
  };
3880
3907
 
3881
3908
  const SpinButton = (props) => {
3909
+ SpinButton.displayName = "SpinButton";
3882
3910
  const classes = useInputStyles$1();
3883
3911
  const { min, max } = props;
3884
3912
  const [value, setValue] = useState(props.value);
@@ -3921,7 +3949,8 @@ const SpinButton = (props) => {
3921
3949
  }
3922
3950
  };
3923
3951
  const id = useId("spin-button");
3924
- return (jsxs("div", { children: [props.infoLabel && jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), jsx(SpinButton$1, { ...props, step: step, id: id, size: "medium", precision: CalculatePrecision(step ?? 1.01), displayValue: props.unit ? `${PrecisionRound(value, CalculatePrecision(step ?? 1.01))} ${props.unit}` : undefined, value: value, onChange: handleChange, onKeyUp: handleKeyUp, onKeyDown: HandleKeyDown, onBlur: HandleOnBlur, className: `${!validateValue(value) ? classes.invalid : classes.valid}` })] }));
3952
+ const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : "", props.className);
3953
+ return (jsxs("div", { className: classes.container, children: [props.infoLabel && jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), jsx(SpinButton$1, { ...props, step: step, id: id, size: "medium", precision: CalculatePrecision(step ?? 1.01), displayValue: props.unit ? `${PrecisionRound(value, CalculatePrecision(step ?? 1.01))} ${props.unit}` : undefined, value: value, onChange: handleChange, onKeyUp: handleKeyUp, onKeyDown: HandleKeyDown, onBlur: HandleOnBlur, className: mergedClassName })] }));
3925
3954
  };
3926
3955
  /**
3927
3956
  * Fluent's CalculatePrecision function
@@ -3972,7 +4001,10 @@ function PrecisionRound(value, precision) {
3972
4001
  * @param props - PropertyLineProps and InputProps
3973
4002
  * @returns property-line wrapped input component
3974
4003
  */
3975
- const TextInputPropertyLine = (props) => (jsx(PropertyLine, { ...props, children: jsx(TextInput, { ...props }) }));
4004
+ const TextInputPropertyLine = (props) => {
4005
+ TextInputPropertyLine.displayName = "TextInputPropertyLine";
4006
+ return (jsx(PropertyLine, { ...props, children: jsx(TextInput, { ...props }) }));
4007
+ };
3976
4008
  /**
3977
4009
  * Wraps a number input in a property line
3978
4010
  * To force integer values, use forceInt param (this is distinct from the 'step' param, which will still allow submitting an integer value. forceInt will not)
@@ -3980,6 +4012,7 @@ const TextInputPropertyLine = (props) => (jsx(PropertyLine, { ...props, children
3980
4012
  * @returns property-line wrapped input component
3981
4013
  */
3982
4014
  const NumberInputPropertyLine = (props) => {
4015
+ NumberInputPropertyLine.displayName = "NumberInputPropertyLine";
3983
4016
  return (jsx(PropertyLine, { ...props, children: jsx(SpinButton, { ...props }) }));
3984
4017
  };
3985
4018
 
@@ -4002,6 +4035,7 @@ const useSyncedSliderStyles = makeStyles({
4002
4035
  * @returns SyncedSlider component
4003
4036
  */
4004
4037
  const SyncedSliderInput = (props) => {
4038
+ SyncedSliderInput.displayName = "SyncedSliderInput";
4005
4039
  const { infoLabel, ...passthroughProps } = props;
4006
4040
  const classes = useSyncedSliderStyles();
4007
4041
  const [value, setValue] = useState(props.value);
@@ -4051,6 +4085,7 @@ const SyncedSliderInput = (props) => {
4051
4085
  * @returns
4052
4086
  */
4053
4087
  const SyncedSliderPropertyLine = forwardRef((props, ref) => {
4088
+ SyncedSliderPropertyLine.displayName = "SyncedSliderPropertyLine";
4054
4089
  const { label, description, ...sliderProps } = props;
4055
4090
  return (jsx(PropertyLine, { ref: ref, ...props, children: jsx(SyncedSliderInput, { ...sliderProps }) }));
4056
4091
  });
@@ -4130,6 +4165,7 @@ const useClasses = makeStyles({
4130
4165
  },
4131
4166
  });
4132
4167
  const MessageBar = (props) => {
4168
+ MessageBar.displayName = "MessageBar";
4133
4169
  const { message, title: header, intent, docLink } = props;
4134
4170
  const classes = useClasses();
4135
4171
  return (jsx("div", { className: classes.container, children: jsx(MessageBar$1, { intent: intent, layout: "multiline", children: jsxs(MessageBarBody, { children: [jsx(MessageBarTitle, { children: header }), message, docLink && (jsxs(Fragment, { children: [" - ", jsx(Link, { href: docLink, target: "_blank", rel: "noopener noreferrer", children: "Learn More" })] }))] }) }) }));
@@ -4237,6 +4273,7 @@ const HasW = (vector) => vector instanceof Vector4 || vector instanceof Quaterni
4237
4273
  * @returns
4238
4274
  */
4239
4275
  const TensorPropertyLine = (props) => {
4276
+ TensorPropertyLine.displayName = "TensorPropertyLine";
4240
4277
  const converted = (val) => (props.valueConverter ? props.valueConverter.from(val) : val);
4241
4278
  const formatted = (val) => converted(val).toFixed(props.step !== undefined ? CalculatePrecision(props.step) : 2);
4242
4279
  const [vector, setVector] = useState(props.value);
@@ -4252,12 +4289,14 @@ const TensorPropertyLine = (props) => {
4252
4289
  };
4253
4290
  const ToDegreesConverter = { from: Tools.ToDegrees, to: Tools.ToRadians };
4254
4291
  const RotationVectorPropertyLine = (props) => {
4292
+ RotationVectorPropertyLine.displayName = "RotationVectorPropertyLine";
4255
4293
  const min = props.useDegrees ? 0 : undefined;
4256
4294
  const max = props.useDegrees ? 360 : undefined;
4257
4295
  return (jsx(Vector3PropertyLine, { ...props, unit: props.useDegrees ? "deg" : "rad", valueConverter: props.useDegrees ? ToDegreesConverter : undefined, min: min, max: max, step: 0.001 }));
4258
4296
  };
4259
4297
  const QuaternionPropertyLineInternal = TensorPropertyLine;
4260
4298
  const QuaternionPropertyLine = (props) => {
4299
+ QuaternionPropertyLine.displayName = "QuaternionPropertyLine";
4261
4300
  const min = props.useDegrees ? 0 : undefined;
4262
4301
  const max = props.useDegrees ? 360 : undefined;
4263
4302
  const [quat, setQuat] = useState(props.value);
@@ -4278,50 +4317,97 @@ const Vector2PropertyLine = TensorPropertyLine;
4278
4317
  const Vector3PropertyLine = TensorPropertyLine;
4279
4318
  const Vector4PropertyLine = TensorPropertyLine;
4280
4319
 
4281
- const useColorPickerStyles = makeStyles({
4282
- colorPickerContainer: {
4283
- width: "325px",
4320
+ const useDropdownStyles = makeStyles({
4321
+ dropdown: { ...UniformWidthStyling, minWidth: CustomTokens.inputWidth },
4322
+ container: {
4284
4323
  display: "flex",
4285
4324
  flexDirection: "column",
4286
- gap: tokens.spacingVerticalMNudge, // 10px
4325
+ justifyContent: "center", // align items vertically
4326
+ gap: "4px",
4327
+ },
4328
+ });
4329
+ /**
4330
+ * Renders a fluent UI dropdown component for the options passed in, and an additional 'Not Defined' option if null is set to true
4331
+ * This component can handle both null and undefined values
4332
+ * @param props
4333
+ * @returns dropdown component
4334
+ */
4335
+ const Dropdown = (props) => {
4336
+ Dropdown.displayName = "Dropdown";
4337
+ const classes = useDropdownStyles();
4338
+ const { options, value } = props;
4339
+ const [defaultVal, setDefaultVal] = useState(props.value);
4340
+ useEffect(() => {
4341
+ setDefaultVal(value);
4342
+ }, [props.value]);
4343
+ const id = useId("dropdown");
4344
+ const mergedClassName = mergeClasses(classes.dropdown, props.className);
4345
+ return (jsxs("div", { className: classes.container, children: [props.infoLabel && jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), jsx(Dropdown$1, { id: id, disabled: props.disabled, size: "medium", className: mergedClassName, onOptionSelect: (evt, data) => {
4346
+ const value = typeof props.value === "number" ? Number(data.optionValue) : data.optionValue;
4347
+ if (value !== undefined) {
4348
+ setDefaultVal(value);
4349
+ props.onChange(value);
4350
+ }
4351
+ }, selectedOptions: [defaultVal.toString()], value: options.find((o) => o.value === defaultVal)?.label, children: options.map((option) => (jsx(Option, { className: classes.dropdown, value: option.value.toString(), disabled: false, children: option.label }, option.label))) })] }));
4352
+ };
4353
+ const NumberDropdown = Dropdown;
4354
+ const StringDropdown = Dropdown;
4355
+
4356
+ const useColorPickerStyles = makeStyles({
4357
+ container: {
4358
+ width: "380px",
4359
+ display: "flex", // becomes a flexbox
4360
+ flexDirection: "column", // with children in a column
4361
+ alignItems: "center", // centers children horizontally
4362
+ justifyContent: "center", // centers children vertically (if height is set)
4363
+ borderRadius: "4px",
4364
+ gap: "15px",
4287
4365
  overflow: "visible",
4288
4366
  },
4367
+ row: {
4368
+ flex: 1, // is a row in the container's flex column
4369
+ display: "flex", // becomes its own flexbox
4370
+ flexDirection: "row", // with children in a row
4371
+ gap: "20px",
4372
+ alignItems: "center", // align items vertically
4373
+ width: "100%",
4374
+ },
4375
+ colorPicker: {
4376
+ flex: 1,
4377
+ width: "350px",
4378
+ height: "350px",
4379
+ },
4289
4380
  previewColor: {
4290
- width: "50px",
4291
- height: "50px",
4292
- borderRadius: tokens.borderRadiusMedium,
4381
+ width: "60px",
4382
+ height: "60px",
4383
+ borderRadius: tokens.borderRadiusMedium, // 4px?
4293
4384
  border: `${tokens.spacingVerticalXXS} solid ${tokens.colorNeutralShadowKeyLighter}`,
4294
4385
  "@media (forced-colors: active)": {
4295
4386
  forcedColorAdjust: "none", // ensures elmement maintains color in high constrast mode
4296
4387
  },
4297
4388
  },
4298
- row: {
4389
+ inputRow: {
4299
4390
  display: "flex",
4300
4391
  flexDirection: "row",
4301
- gap: tokens.spacingVerticalM, // 12px
4302
- alignItems: "center",
4392
+ flex: 1, // grow and fill available space
4393
+ justifyContent: "center",
4394
+ gap: "10px",
4395
+ width: "100%",
4303
4396
  },
4304
- colorFieldWrapper: {
4305
- display: "flex",
4306
- flexDirection: "column",
4397
+ inputField: {
4398
+ flex: 1, // grow and fill available space
4399
+ width: "auto",
4400
+ minWidth: 0,
4307
4401
  gap: tokens.spacingVerticalSNudge, // 6px
4308
4402
  },
4309
- input: {
4310
- width: "80px",
4311
- },
4312
- spinButton: {
4313
- width: "50px",
4314
- },
4315
- container: {
4316
- display: "flex",
4317
- flexDirection: "column",
4318
- gap: tokens.spacingVerticalL, // 16px
4319
- },
4320
4403
  });
4321
4404
  const ColorPickerPopup = (props) => {
4405
+ ColorPickerPopup.displayName = "ColorPickerPopup";
4322
4406
  const classes = useColorPickerStyles();
4323
4407
  const [color, setColor] = useState(props.value);
4324
4408
  const [popoverOpen, setPopoverOpen] = useState(false);
4409
+ const [isLinear, setIsLinear] = useState(props.isLinearMode ?? false);
4410
+ const [isFloat, setFloat] = useState(false);
4325
4411
  useEffect(() => {
4326
4412
  setColor(props.value); // Ensures the trigger color updates when props.value changes
4327
4413
  }, [props.value]);
@@ -4340,9 +4426,21 @@ const ColorPickerPopup = (props) => {
4340
4426
  align: "start",
4341
4427
  overflowBoundary: document.body,
4342
4428
  autoSize: true,
4343
- }, open: popoverOpen, trapFocus: true, onOpenChange: (_, data) => setPopoverOpen(data.open), children: [jsx(PopoverTrigger, { disableButtonEnhancement: true, children: jsx(ColorSwatch, { borderColor: tokens.colorNeutralShadowKeyDarker, size: "small", color: color.toHexString(), value: color.toHexString().slice(1) }) }), jsx(PopoverSurface, { children: jsxs("div", { className: classes.colorPickerContainer, children: [jsxs(ColorPicker, { color: rgbaToHsv(color), onColorChange: handleColorPickerChange, children: [jsx(ColorArea, { inputX: { "aria-label": "Saturation" }, inputY: { "aria-label": "Brightness" } }), jsx(ColorSlider, { "aria-label": "Hue" }), color instanceof Color4 && jsx(AlphaSlider, { "aria-label": "Alpha" })] }), jsxs("div", { className: classes.container, children: [jsxs("div", { className: classes.row, children: [jsx("div", { className: classes.previewColor, style: { backgroundColor: color.toHexString() } }), jsx(InputHexField, { title: "Gamma Hex", value: color, isLinearMode: props.isLinearMode, onChange: handleChange }), jsx(InputHexField, { title: "Linear Hex", linearHex: true, isLinearMode: props.isLinearMode, value: color, onChange: handleChange })] }), jsxs("div", { className: classes.row, children: [jsx(InputRgbField, { title: "Red", value: color, rgbKey: "r", onChange: handleChange }), jsx(InputRgbField, { title: "Green", value: color, rgbKey: "g", onChange: handleChange }), jsx(InputRgbField, { title: "Blue", value: color, rgbKey: "b", onChange: handleChange }), jsx(InputAlphaField, { color: color, onChange: handleChange })] }), jsxs("div", { className: classes.row, children: [jsx(InputHsvField, { title: "Hue", value: color, hsvKey: "h", max: 360, onChange: handleChange }), jsx(InputHsvField, { title: "Saturation", value: color, hsvKey: "s", max: 100, scale: 100, onChange: handleChange }), jsx(InputHsvField, { title: "Value", value: color, hsvKey: "v", max: 100, scale: 100, onChange: handleChange })] })] })] }) })] }));
4344
- };
4345
- const HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/);
4429
+ }, open: popoverOpen, trapFocus: true, onOpenChange: (_, data) => setPopoverOpen(data.open), children: [jsx(PopoverTrigger, { disableButtonEnhancement: true, children: jsx(ColorSwatch, { borderColor: tokens.colorNeutralShadowKeyDarker, size: "small", color: color.toHexString(), value: color.toHexString().slice(1) }) }), jsx(PopoverSurface, { children: jsxs("div", { className: classes.container, children: [jsxs(ColorPicker, { className: classes.colorPicker, color: rgbaToHsv(color), onColorChange: handleColorPickerChange, children: [jsx(ColorArea, { inputX: { "aria-label": "Saturation" }, inputY: { "aria-label": "Brightness" } }), jsx(ColorSlider, { "aria-label": "Hue" }), color instanceof Color4 && jsx(AlphaSlider, { "aria-label": "Alpha" })] }), jsxs("div", { className: classes.row, children: [jsx("div", { className: classes.previewColor, style: { backgroundColor: color.toHexString() } }), jsx(NumberDropdown, { className: classes.inputField, infoLabel: {
4430
+ label: "Color Space",
4431
+ info: jsx(Body1, { children: "Today this is not mutable as the color space is determined by the entity. Soon we will allow swapping" }),
4432
+ }, options: [
4433
+ { label: "Gamma", value: 0 },
4434
+ { label: "Linear", value: 1 },
4435
+ ], disabled: true, value: isLinear ? 1 : 0, onChange: (val) => setIsLinear(val === 1) }), jsx(NumberDropdown, { className: classes.inputField, infoLabel: {
4436
+ label: "Data Type",
4437
+ info: jsx(Body1, { children: "We will introduce this functionality soon!" }),
4438
+ }, options: [
4439
+ { label: "Int", value: 0 },
4440
+ { label: "Float", value: 1 },
4441
+ ], disabled: true, value: isFloat ? 1 : 0, onChange: (val) => setFloat(val === 1) })] }), jsxs("div", { className: classes.inputRow, children: [jsx(InputRgbField, { title: "Red", value: color, rgbKey: "r", onChange: handleChange }), jsx(InputRgbField, { title: "Green", value: color, rgbKey: "g", onChange: handleChange }), jsx(InputRgbField, { title: "Blue", value: color, rgbKey: "b", onChange: handleChange }), jsx(InputAlphaField, { color: color, onChange: handleChange })] }), jsxs("div", { className: classes.inputRow, children: [jsx(InputHsvField, { title: "Hue", value: color, hsvKey: "h", max: 360, onChange: handleChange }), jsx(InputHsvField, { title: "Saturation", value: color, hsvKey: "s", max: 100, scale: 100, onChange: handleChange }), jsx(InputHsvField, { title: "Value", value: color, hsvKey: "v", max: 100, scale: 100, onChange: handleChange })] }), jsx("div", { className: classes.inputRow, children: jsx(InputHexField, { title: "Hexadecimal", linearHex: isLinear, isLinearMode: isLinear, value: color, onChange: handleChange }) })] }) })] }));
4442
+ };
4443
+ const HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8})$/);
4346
4444
  /**
4347
4445
  * Component which displays the passed in color's HEX value, either in linearSpace (if linearHex is true) or in gamma space
4348
4446
  * When the hex color is changed by user, component calculates the new Color3/4 value and calls onChange
@@ -4352,18 +4450,18 @@ const HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/);
4352
4450
  * @returns
4353
4451
  */
4354
4452
  const InputHexField = (props) => {
4355
- const styles = useColorPickerStyles();
4453
+ const classes = useColorPickerStyles();
4356
4454
  const { title, value, onChange, linearHex, isLinearMode } = props;
4357
- return (jsx("div", { className: styles.colorFieldWrapper, children: jsx(TextInput, { disabled: linearHex ? !isLinearMode : false, className: styles.input, value: linearHex ? value.toLinearSpace().toHexString() : value.toHexString(), validator: (val) => val != "" && HEX_REGEX.test(val), onChange: (val) => (linearHex ? onChange(Color3.FromHexString(val).toGammaSpace()) : onChange(Color3.FromHexString(val))), infoLabel: title
4358
- ? {
4359
- label: title,
4360
- // If not representing a linearHex, no info is needed.
4361
- info: !props.linearHex ? undefined : !isLinearMode ? ( // If representing a linear hex but we are in gammaMode, simple message explaining why linearHex is disabled
4362
- jsx(Fragment, { children: " This color picker is attached to an entity whose color is stored in gamma space, so we are showing linear hex in disabled view " })) : (
4363
- // If representing a linear hex and we are in linearMode, give information about how to use these hex values
4364
- jsxs(Fragment, { children: ["This color picker is attached to an entity whose color is stored in linear space (ex: PBR Material), and Babylon converts the color to gamma space before rendering on screen because the human eye is best at processing colors in gamma space. We thus also want to display the color picker in gamma space so that the color chosen here will match the color seen in your entity.", jsx("br", {}), "If you want to copy/paste the HEX into your code, you can either use", jsx(Body1Strong, { children: "Color3.FromHexString(LINEAR_HEX)" }), jsx("br", {}), "or", jsx("br", {}), jsx(Body1Strong, { children: "Color3.FromHexString(GAMMA_HEX).toLinearSpace()" }), jsx("br", {}), jsx("br", {}), jsx(Link, { href: "https://doc.babylonjs.com/preparingArtForBabylon/controllingColorSpace/", children: " Read more in our docs! " })] })),
4365
- }
4366
- : undefined }) }));
4455
+ return (jsx(TextInput, { disabled: linearHex ? !isLinearMode : false, className: classes.inputField, value: linearHex ? value.toLinearSpace().toHexString() : value.toHexString(), validator: (val) => val != "" && HEX_REGEX.test(val), onChange: (val) => (linearHex ? onChange(Color3.FromHexString(val).toGammaSpace()) : onChange(Color3.FromHexString(val))), infoLabel: title
4456
+ ? {
4457
+ label: title,
4458
+ // If not representing a linearHex, no info is needed.
4459
+ info: !props.linearHex ? undefined : !isLinearMode ? ( // If representing a linear hex but we are in gammaMode, simple message explaining why linearHex is disabled
4460
+ jsx(Fragment, { children: " This color picker is attached to an entity whose color is stored in gamma space, so we are showing linear hex in disabled view " })) : (
4461
+ // If representing a linear hex and we are in linearMode, give information about how to use these hex values
4462
+ jsxs(Fragment, { children: ["This color picker is attached to an entity whose color is stored in linear space (ex: PBR Material), and Babylon converts the color to gamma space before rendering on screen because the human eye is best at processing colors in gamma space. We thus also want to display the color picker in gamma space so that the color chosen here will match the color seen in your entity.", jsx("br", {}), "If you want to copy/paste the HEX into your code, you can either use", jsx(Body1Strong, { children: "Color3.FromHexString(LINEAR_HEX)" }), jsx("br", {}), "or", jsx("br", {}), jsx(Body1Strong, { children: "Color3.FromHexString(GAMMA_HEX).toLinearSpace()" }), jsx("br", {}), jsx("br", {}), jsx(Link, { href: "https://doc.babylonjs.com/preparingArtForBabylon/controllingColorSpace/", children: " Read more in our docs! " })] })),
4463
+ }
4464
+ : undefined }));
4367
4465
  };
4368
4466
  const InputRgbField = (props) => {
4369
4467
  const { value, onChange, title, rgbKey } = props;
@@ -4373,7 +4471,7 @@ const InputRgbField = (props) => {
4373
4471
  newColor[rgbKey] = val / 255.0; // Convert to 0-1 range
4374
4472
  onChange(newColor);
4375
4473
  }, [value, onChange, rgbKey]);
4376
- return (jsx("div", { className: classes.colorFieldWrapper, children: jsx(SpinButton, { title: title, infoLabel: title ? { label: title } : undefined, className: classes.spinButton, min: 0, max: 255, value: Math.round(value[rgbKey] * 255), forceInt: true, onChange: handleChange }) }));
4474
+ return (jsx(SpinButton, { title: title, infoLabel: title ? { label: title } : undefined, className: classes.inputField, min: 0, max: 255, value: Math.round(value[rgbKey] * 255), forceInt: true, onChange: handleChange }));
4377
4475
  };
4378
4476
  function rgbaToHsv(color) {
4379
4477
  const c = new Color3(color.r, color.g, color.b);
@@ -4399,7 +4497,7 @@ const InputHsvField = (props) => {
4399
4497
  }
4400
4498
  props.onChange(newColor);
4401
4499
  }, [value, onChange, hsvKey, scale]);
4402
- return (jsx("div", { className: classes.colorFieldWrapper, children: jsx(SpinButton, { infoLabel: title ? { label: title } : undefined, title: title, className: classes.spinButton, min: 0, max: max, value: Math.round(rgbaToHsv(value)[hsvKey] * scale), forceInt: true, onChange: handleChange }) }));
4500
+ return (jsx(SpinButton, { infoLabel: title ? { label: title } : undefined, title: title, className: classes.inputField, min: 0, max: max, value: Math.round(rgbaToHsv(value)[hsvKey] * scale), forceInt: true, onChange: handleChange }));
4403
4501
  };
4404
4502
  /**
4405
4503
  * Displays the alpha value of a color, either in the disabled state (if color is Color3) or as a spin button (if color is Color4).
@@ -4422,10 +4520,10 @@ const InputAlphaField = (props) => {
4422
4520
  return Color4.FromColor3(color, value);
4423
4521
  }
4424
4522
  }, [onChange]);
4425
- return (jsx("div", { className: classes.colorFieldWrapper, children: jsx(SpinButton, { disabled: color instanceof Color3, min: 0, max: 1, className: classes.spinButton, value: color instanceof Color3 ? 1 : color.a, step: 0.01, onChange: handleChange, infoLabel: {
4426
- label: "Alpha",
4427
- info: color instanceof Color3 ? (jsx(Fragment, { children: "Because this color picker is representing a Color3, we do not permit modifying alpha from the color picker. You can however modify the entity's alpha property directly, either in code via entity.alpha OR via inspector's transparency section." })) : undefined,
4428
- } }) }));
4523
+ return (jsx(SpinButton, { disabled: color instanceof Color3, min: 0, max: 1, className: classes.inputField, value: color instanceof Color3 ? 1 : color.a, step: 0.01, onChange: handleChange, infoLabel: {
4524
+ label: "Alpha",
4525
+ info: color instanceof Color3 ? (jsx(Fragment, { children: "Because this color picker is representing a Color3, we do not permit modifying alpha from the color picker. You can however modify the entity's alpha property directly, either in code via entity.alpha OR via inspector's transparency section." })) : undefined,
4526
+ } }));
4429
4527
  };
4430
4528
 
4431
4529
  /**
@@ -4435,6 +4533,7 @@ const InputAlphaField = (props) => {
4435
4533
  * @returns Component wrapping a colorPicker component with a property line
4436
4534
  */
4437
4535
  const ColorPropertyLine = forwardRef((props, ref) => {
4536
+ ColorPropertyLine.displayName = "ColorPropertyLine";
4438
4537
  const [color, setColor] = useState(props.value);
4439
4538
  const onSliderChange = (value, key) => {
4440
4539
  let newColor;
@@ -4558,39 +4657,13 @@ const ArcRotateCameraBehaviorsProperties = (props) => {
4558
4657
  return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Auto Rotation", target: camera, propertyKey: "useAutoRotationBehavior" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Bouncing", target: camera, propertyKey: "useBouncingBehavior" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Framing", target: camera, propertyKey: "useFramingBehavior" })] }));
4559
4658
  };
4560
4659
 
4561
- const useDropdownStyles = makeStyles({
4562
- dropdown: { ...UniformWidthStyling, minWidth: CustomTokens.inputWidth },
4563
- });
4564
- /**
4565
- * Renders a fluent UI dropdown component for the options passed in, and an additional 'Not Defined' option if null is set to true
4566
- * This component can handle both null and undefined values
4567
- * @param props
4568
- * @returns dropdown component
4569
- */
4570
- const Dropdown = (props) => {
4571
- const classes = useDropdownStyles();
4572
- const { options, value } = props;
4573
- const [defaultVal, setDefaultVal] = useState(props.value);
4574
- useEffect(() => {
4575
- setDefaultVal(value);
4576
- }, [props.value]);
4577
- return (jsx(Dropdown$1, { disabled: props.disabled, size: "medium", className: classes.dropdown, onOptionSelect: (evt, data) => {
4578
- const value = typeof props.value === "number" ? Number(data.optionValue) : data.optionValue;
4579
- if (value !== undefined) {
4580
- setDefaultVal(value);
4581
- props.onChange(value);
4582
- }
4583
- }, selectedOptions: [defaultVal.toString()], value: options.find((o) => o.value === defaultVal)?.label, children: options.map((option) => (jsx(Option, { className: classes.dropdown, value: option.value.toString(), disabled: false, children: option.label }, option.label))) }));
4584
- };
4585
- const NumberDropdown = Dropdown;
4586
- const StringDropdown = Dropdown;
4587
-
4588
4660
  /**
4589
4661
  * Wraps a dropdown in a property line
4590
4662
  * @param props - PropertyLineProps and DropdownProps
4591
4663
  * @returns property-line wrapped dropdown
4592
4664
  */
4593
4665
  const DropdownPropertyLine = forwardRef((props, ref) => {
4666
+ DropdownPropertyLine.displayName = "DropdownPropertyLine";
4594
4667
  return (jsx(PropertyLine, { ...props, ref: ref, children: jsx(Dropdown, { ...props }) }));
4595
4668
  });
4596
4669
  /**
@@ -5380,6 +5453,7 @@ const useInputStyles = makeStyles({
5380
5453
  * @returns
5381
5454
  */
5382
5455
  const Textarea = (props) => {
5456
+ Textarea.displayName = "Textarea";
5383
5457
  const classes = useInputStyles();
5384
5458
  const handleChange = (event, _data) => {
5385
5459
  event.stopPropagation(); // Prevent event propagation
@@ -5501,7 +5575,7 @@ function SaveMetadata(entity, metadata) {
5501
5575
  entity.metadata = metadata;
5502
5576
  }
5503
5577
  }
5504
- const useStyles$3 = makeStyles({
5578
+ const useStyles$4 = makeStyles({
5505
5579
  buttonDiv: {
5506
5580
  display: "grid",
5507
5581
  gridAutoFlow: "column",
@@ -5516,7 +5590,7 @@ const useStyles$3 = makeStyles({
5516
5590
  */
5517
5591
  const MetadataProperties = (props) => {
5518
5592
  const { entity } = props;
5519
- const classes = useStyles$3();
5593
+ const classes = useStyles$4();
5520
5594
  const metadata = useProperty(entity, "metadata");
5521
5595
  const stringifiedMetadata = useMemo(() => StringifyMetadata(metadata) ?? "", [metadata]);
5522
5596
  const metadataType = useMemo(() => GetMetadataEntityType(metadata), [metadata]);
@@ -5990,6 +6064,7 @@ const useGradientStyles = makeStyles({
5990
6064
  * @returns A React component
5991
6065
  */
5992
6066
  const Gradient = (props) => {
6067
+ Gradient.displayName = "Gradient";
5993
6068
  const [gradient, setGradient] = useState(props.value);
5994
6069
  const classes = useGradientStyles();
5995
6070
  useEffect(() => {
@@ -6046,6 +6121,7 @@ function GradientsToListItems(gradients) {
6046
6121
  })) ?? []);
6047
6122
  }
6048
6123
  const FactorGradientList = (props) => {
6124
+ FactorGradientList.displayName = "FactorGradientList";
6049
6125
  const { gradients } = props;
6050
6126
  const items = GradientsToListItems(gradients);
6051
6127
  return (jsx(List, { addButtonLabel: items.length > 0 ? `Add new ${props.label}` : `Use ${props.label}s`, items: items, onDelete: (item) => props.removeGradient(item.data), onAdd: () => {
@@ -6065,6 +6141,7 @@ const FactorGradientList = (props) => {
6065
6141
  } }, "Factor"));
6066
6142
  };
6067
6143
  const Color3GradientList = (props) => {
6144
+ Color3GradientList.displayName = "Color3GradientList";
6068
6145
  const { gradients } = props;
6069
6146
  const items = GradientsToListItems(gradients);
6070
6147
  return (jsx(List, { addButtonLabel: items.length > 0 ? `Add new ${props.label}` : `Use ${props.label}s`, items: items, onDelete: (item) => props.removeGradient(item.data), onAdd: () => {
@@ -6083,6 +6160,7 @@ const Color3GradientList = (props) => {
6083
6160
  } }, "Color3"));
6084
6161
  };
6085
6162
  const Color4GradientList = (props) => {
6163
+ Color4GradientList.displayName = "Color4GradientList";
6086
6164
  const { gradients } = props;
6087
6165
  const items = GradientsToListItems(gradients);
6088
6166
  return (jsx(List, { addButtonLabel: items.length > 0 ? `Add new ${props.label}` : `Use ${props.label}s`, items: items, onDelete: (item) => props.removeGradient(item.data), onAdd: () => {
@@ -6377,6 +6455,7 @@ const PhysicsPropertiesServiceDefinition = {
6377
6455
  * @returns Checkbox component
6378
6456
  */
6379
6457
  const Checkbox = (props) => {
6458
+ Checkbox.displayName = "Checkbox";
6380
6459
  const [checked, setChecked] = useState(() => props.value ?? false);
6381
6460
  useEffect(() => {
6382
6461
  if (props.value != undefined) {
@@ -6396,6 +6475,7 @@ const Checkbox = (props) => {
6396
6475
  * @returns property-line wrapped checkbox
6397
6476
  */
6398
6477
  const CheckboxPropertyLine = (props) => {
6478
+ CheckboxPropertyLine.displayName = "CheckboxPropertyLine";
6399
6479
  return (jsx(PropertyLine, { ...props, children: jsx(Checkbox, { ...props }) }));
6400
6480
  };
6401
6481
 
@@ -6885,6 +6965,180 @@ function FindTextureType(type) {
6885
6965
  return null;
6886
6966
  }
6887
6967
 
6968
+ const useStyles$3 = makeStyles({
6969
+ root: { display: "flex", flexDirection: "column", gap: "8px" },
6970
+ controls: {
6971
+ display: "flex",
6972
+ gap: "2px",
6973
+ padding: "2px",
6974
+ width: "100%",
6975
+ justifyContent: "center",
6976
+ },
6977
+ controlButton: {
6978
+ minWidth: "auto",
6979
+ flex: "1 1 0", // Equal flex grow/shrink with 0 basis
6980
+ paddingVertical: "4px",
6981
+ paddingHorizontal: "8px",
6982
+ overflow: "hidden",
6983
+ textOverflow: "ellipsis",
6984
+ },
6985
+ preview: {
6986
+ border: "1px solid #ccc",
6987
+ marginTop: "8px",
6988
+ maxWidth: "100%",
6989
+ marginLeft: "auto",
6990
+ marginRight: "auto",
6991
+ display: "block",
6992
+ },
6993
+ });
6994
+ // This method of holding TextureChannels was brought over from inspectorv1 and can likely be refactored/simplified
6995
+ const TextureChannelStates = {
6996
+ R: { R: true, G: false, B: false, A: false },
6997
+ G: { R: false, G: true, B: false, A: false },
6998
+ B: { R: false, G: false, B: true, A: false },
6999
+ A: { R: false, G: false, B: false, A: true },
7000
+ ALL: { R: true, G: true, B: true, A: true },
7001
+ };
7002
+ const TexturePreview = (props) => {
7003
+ const { texture, width, height } = props;
7004
+ const classes = useStyles$3();
7005
+ const canvasRef = useRef(null);
7006
+ const [channels, setChannels] = useState(TextureChannelStates.ALL);
7007
+ const [face, setFace] = useState(0);
7008
+ const internalTexture = useProperty(texture, "_texture");
7009
+ const updatePreviewCanvasSize = useCallback((previewCanvas) => {
7010
+ // This logic was brought over from inspectorv1 and can likely be refactored/simplified
7011
+ const size = texture.getSize();
7012
+ const ratio = size.width / size.height;
7013
+ let w = width;
7014
+ let h = (w / ratio) | 1;
7015
+ const engine = texture.getScene()?.getEngine();
7016
+ if (engine && h > engine.getCaps().maxTextureSize) {
7017
+ w = size.width;
7018
+ h = size.height;
7019
+ }
7020
+ previewCanvas.width = w;
7021
+ previewCanvas.height = h;
7022
+ previewCanvas.style.width = w + "px";
7023
+ previewCanvas.style.height = h + "px";
7024
+ return {
7025
+ w: w,
7026
+ h: h,
7027
+ };
7028
+ }, [canvasRef.current, texture, width, height, internalTexture]);
7029
+ const updatePreviewAsync = useCallback(async () => {
7030
+ const previewCanvas = canvasRef.current;
7031
+ if (!previewCanvas) {
7032
+ return;
7033
+ }
7034
+ try {
7035
+ await WhenTextureReadyAsync(texture); // Ensure texture is loaded before grabbing size
7036
+ const { w, h } = updatePreviewCanvasSize(previewCanvas); // Grab desired size
7037
+ const data = await ApplyChannelsToTextureDataAsync(texture, w, h, face, channels); // get channel data to load onto canvas context
7038
+ const context = previewCanvas.getContext("2d");
7039
+ if (context) {
7040
+ const imageData = context.createImageData(w, h);
7041
+ imageData.data.set(data);
7042
+ context.putImageData(imageData, 0, 0);
7043
+ }
7044
+ }
7045
+ catch {
7046
+ updatePreviewCanvasSize(previewCanvas); // If we fail above, best effort sizing preview canvas
7047
+ }
7048
+ }, [[texture, width, height, face, channels, internalTexture]]);
7049
+ useEffect(() => {
7050
+ void updatePreviewAsync();
7051
+ }, [texture, width, height, face, channels, internalTexture]);
7052
+ return (jsxs("div", { className: classes.root, children: [texture.isCube ? (jsx(Toolbar$1, { className: classes.controls, "aria-label": "Cube Faces", children: ["+X", "-X", "+Y", "-Y", "+Z", "-Z"].map((label, idx) => (jsx(ToolbarButton, { className: classes.controlButton, appearance: face === idx ? "primary" : "subtle", onClick: () => setFace(idx), children: label }, label))) })) : (jsx(Toolbar$1, { className: classes.controls, "aria-label": "Channels", children: ["R", "G", "B", "A", "ALL"].map((ch) => (jsx(ToolbarButton, { className: classes.controlButton, appearance: channels === TextureChannelStates[ch] ? "primary" : "subtle", onClick: () => setChannels(TextureChannelStates[ch]), children: ch }, ch))) })), jsx("canvas", { ref: canvasRef, className: classes.preview }), texture.isRenderTarget && (jsx(Button$1, { appearance: "outline", onClick: () => {
7053
+ void updatePreviewAsync();
7054
+ }, children: "Refresh" }))] }));
7055
+ };
7056
+ /**
7057
+ * Gets the data of the specified texture by rendering it to an intermediate RGBA texture and retrieving the bytes from it.
7058
+ * This is convienent to get 8-bit RGBA values for a texture in a GPU compressed format.
7059
+ * @param texture the source texture
7060
+ * @param width the width of the result, which does not have to match the source texture width
7061
+ * @param height the height of the result, which does not have to match the source texture height
7062
+ * @param face if the texture has multiple faces, the face index to use for the source
7063
+ * @param channels a filter for which of the RGBA channels to return in the result
7064
+ * @param lod if the texture has multiple LODs, the lod index to use for the source
7065
+ * @returns the 8-bit texture data
7066
+ */
7067
+ async function ApplyChannelsToTextureDataAsync(texture, width, height, face, channels, lod = 0) {
7068
+ const data = await GetTextureDataAsync(texture, width, height, face, lod);
7069
+ if (!channels.R || !channels.G || !channels.B || !channels.A) {
7070
+ for (let i = 0; i < width * height * 4; i += 4) {
7071
+ // If alpha is the only channel, just display alpha across all channels
7072
+ if (channels.A && !channels.R && !channels.G && !channels.B) {
7073
+ data[i] = data[i + 3];
7074
+ data[i + 1] = data[i + 3];
7075
+ data[i + 2] = data[i + 3];
7076
+ data[i + 3] = 255;
7077
+ continue;
7078
+ }
7079
+ let r = data[i], g = data[i + 1], b = data[i + 2], a = data[i + 3];
7080
+ // If alpha is not visible, make everything 100% alpha
7081
+ if (!channels.A) {
7082
+ a = 255;
7083
+ }
7084
+ // If only one color channel is selected, map both colors to it. If two are selected, the unused one gets set to 0
7085
+ if (!channels.R) {
7086
+ if (channels.G && !channels.B) {
7087
+ r = g;
7088
+ }
7089
+ else if (channels.B && !channels.G) {
7090
+ r = b;
7091
+ }
7092
+ else {
7093
+ r = 0;
7094
+ }
7095
+ }
7096
+ if (!channels.G) {
7097
+ if (channels.R && !channels.B) {
7098
+ g = r;
7099
+ }
7100
+ else if (channels.B && !channels.R) {
7101
+ g = b;
7102
+ }
7103
+ else {
7104
+ g = 0;
7105
+ }
7106
+ }
7107
+ if (!channels.B) {
7108
+ if (channels.R && !channels.G) {
7109
+ b = r;
7110
+ }
7111
+ else if (channels.G && !channels.R) {
7112
+ b = g;
7113
+ }
7114
+ else {
7115
+ b = 0;
7116
+ }
7117
+ }
7118
+ data[i] = r;
7119
+ data[i + 1] = g;
7120
+ data[i + 2] = b;
7121
+ data[i + 3] = a;
7122
+ }
7123
+ }
7124
+ //To flip image on Y axis.
7125
+ if (texture.invertY || texture.isCube) {
7126
+ const numberOfChannelsByLine = width * 4;
7127
+ const halfHeight = height / 2;
7128
+ for (let i = 0; i < halfHeight; i++) {
7129
+ for (let j = 0; j < numberOfChannelsByLine; j++) {
7130
+ const currentCell = j + i * numberOfChannelsByLine;
7131
+ const targetLine = height - i - 1;
7132
+ const targetCell = j + targetLine * numberOfChannelsByLine;
7133
+ const temp = data[currentCell];
7134
+ data[currentCell] = data[targetCell];
7135
+ data[targetCell] = temp;
7136
+ }
7137
+ }
7138
+ }
7139
+ return data;
7140
+ }
7141
+
6888
7142
  const BaseTexturePreviewProperties = (props) => {
6889
7143
  const { texture } = props;
6890
7144
  const isUpdatable = texture instanceof Texture || texture instanceof CubeTexture;
@@ -6911,11 +7165,11 @@ const BaseTexturePreviewProperties = (props) => {
6911
7165
  };
6912
7166
  }, undefined, true);
6913
7167
  }, [texture]);
6914
- return (jsxs(Fragment, { children: [jsx(PlaceholderPropertyLine, { label: "TODO: Texture Preview", value: null, onChange: () => { } }), isUpdatable && (jsx(FileUploadLine, { label: "Load Texture From File", accept: ".jpg, .png, .tga, .dds, .env, .exr", onClick: (files) => {
7168
+ return (jsxs(Fragment, { children: [jsx(TexturePreview, { texture: texture, width: 256, height: 256 }), isUpdatable && (jsx(FileUploadLine, { label: "Load Texture From File", accept: ".jpg, .png, .tga, .dds, .env, .exr", onClick: (files) => {
6915
7169
  if (files.length > 0) {
6916
7170
  updateTexture(files[0]);
6917
7171
  }
6918
- } })), jsx(PlaceholderPropertyLine, { label: "TODO:Texture Editor", value: null, onChange: () => { } })] }));
7172
+ } })), jsx(ButtonLine, { label: "Edit Texture (coming soon!)", onClick: () => { } })] }));
6919
7173
  };
6920
7174
  const BaseTextureGeneralProperties = (props) => {
6921
7175
  const { texture } = props;
@@ -8273,6 +8527,7 @@ const useStyles$2 = makeStyles({
8273
8527
  * @returns
8274
8528
  */
8275
8529
  const ComboBox = (props) => {
8530
+ ComboBox.displayName = "ComboBox";
8276
8531
  const comboId = useId();
8277
8532
  const styles = useStyles$2();
8278
8533
  const [query, setQuery] = useState("");
@@ -8333,6 +8588,7 @@ const useDraggableStyles = makeStyles({
8333
8588
  },
8334
8589
  });
8335
8590
  const DraggableLine = (props) => {
8591
+ DraggableLine.displayName = "DraggableLine";
8336
8592
  const classes = useDraggableStyles();
8337
8593
  return (jsxs("div", { className: classes.draggable, title: props.tooltip, draggable: true, onDragStart: (event) => {
8338
8594
  event.dataTransfer.setData(props.format, props.data);
@@ -8345,6 +8601,7 @@ const DraggableLine = (props) => {
8345
8601
  * @returns The positioned popover component
8346
8602
  */
8347
8603
  const PositionedPopover = (props) => {
8604
+ PositionedPopover.displayName = "PositionedPopover";
8348
8605
  const [open, setOpen] = useState(false);
8349
8606
  useEffect(() => {
8350
8607
  setOpen(props.visible);
@@ -8373,6 +8630,7 @@ const useStyles$1 = makeStyles({
8373
8630
  },
8374
8631
  });
8375
8632
  const SearchBar = forwardRef((props, ref) => {
8633
+ SearchBar.displayName = "SearchBar";
8376
8634
  const classes = useStyles$1();
8377
8635
  const onChange = (_, data) => {
8378
8636
  props.onChange(data.value);
@@ -8442,6 +8700,7 @@ const useSearchBoxStyles = makeStyles({
8442
8700
  * @returns The search box component
8443
8701
  */
8444
8702
  const SearchBox = (props) => {
8703
+ SearchBox.displayName = "SearchBox";
8445
8704
  const classes = useSearchBoxStyles();
8446
8705
  const [selectedIndex, setSelectedIndex] = useState(0);
8447
8706
  const [items, setItems] = useState(props.items);
@@ -8503,10 +8762,14 @@ const Pane = (props) => {
8503
8762
  * @returns property-line wrapped input hex component
8504
8763
  */
8505
8764
  const HexPropertyLine = (props) => {
8765
+ HexPropertyLine.displayName = "HexPropertyLine";
8506
8766
  return (jsx(PropertyLine, { ...props, children: jsx(InputHexField, { ...props }) }));
8507
8767
  };
8508
8768
 
8509
- const SpinButtonPropertyLine = (props) => (jsx(PropertyLine, { ...props, children: jsx(SpinButton, { ...props }) }));
8769
+ const SpinButtonPropertyLine = (props) => {
8770
+ SpinButtonPropertyLine.displayName = "SpinButtonPropertyLine";
8771
+ return (jsx(PropertyLine, { ...props, children: jsx(SpinButton, { ...props }) }));
8772
+ };
8510
8773
 
8511
8774
  /**
8512
8775
  * Wraps textarea in a property line
@@ -8514,6 +8777,7 @@ const SpinButtonPropertyLine = (props) => (jsx(PropertyLine, { ...props, childre
8514
8777
  * @returns property-line wrapped text
8515
8778
  */
8516
8779
  const TextAreaPropertyLine = (props) => {
8780
+ TextAreaPropertyLine.displayName = "TextAreaPropertyLine";
8517
8781
  return (jsx(PropertyLine, { ...props, children: jsx(Textarea, { ...props }) }));
8518
8782
  };
8519
8783