@babylonjs/shared-ui-components 8.13.0 → 8.13.1
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/fluent/hoc/buttonLine.d.ts +5 -3
- package/fluent/hoc/buttonLine.js.map +1 -1
- package/fluent/hoc/checkboxPropertyLine.d.ts +9 -0
- package/fluent/hoc/checkboxPropertyLine.js +12 -0
- package/fluent/hoc/checkboxPropertyLine.js.map +1 -0
- package/fluent/hoc/colorPropertyLine.d.ts +4 -11
- package/fluent/hoc/colorPropertyLine.js +25 -7
- package/fluent/hoc/colorPropertyLine.js.map +1 -1
- package/fluent/hoc/dropdownPropertyLine.d.ts +9 -0
- package/fluent/hoc/dropdownPropertyLine.js +12 -0
- package/fluent/hoc/dropdownPropertyLine.js.map +1 -0
- package/fluent/hoc/fileUploadLine.d.ts +8 -0
- package/fluent/hoc/fileUploadLine.js +18 -0
- package/fluent/hoc/fileUploadLine.js.map +1 -0
- package/fluent/hoc/hexLineComponent.d.ts +9 -0
- package/fluent/hoc/hexLineComponent.js +12 -0
- package/fluent/hoc/hexLineComponent.js.map +1 -0
- package/fluent/hoc/inputPropertyLine.d.ts +5 -0
- package/fluent/hoc/inputPropertyLine.js +14 -0
- package/fluent/hoc/inputPropertyLine.js.map +1 -0
- package/fluent/hoc/propertyLine.d.ts +30 -3
- package/fluent/hoc/propertyLine.js +32 -15
- package/fluent/hoc/propertyLine.js.map +1 -1
- package/fluent/hoc/switchPropertyLine.d.ts +1 -1
- package/fluent/hoc/switchPropertyLine.js.map +1 -1
- package/fluent/hoc/syncedSliderLine.d.ts +5 -21
- package/fluent/hoc/syncedSliderLine.js +3 -10
- package/fluent/hoc/syncedSliderLine.js.map +1 -1
- package/fluent/hoc/vectorPropertyLine.d.ts +30 -11
- package/fluent/hoc/vectorPropertyLine.js +23 -6
- package/fluent/hoc/vectorPropertyLine.js.map +1 -1
- package/fluent/primitives/accordion.d.ts +6 -0
- package/fluent/primitives/accordion.js +32 -0
- package/fluent/primitives/accordion.js.map +1 -0
- package/fluent/primitives/checkbox.d.ts +2 -1
- package/fluent/primitives/checkbox.js +7 -7
- package/fluent/primitives/checkbox.js.map +1 -1
- package/fluent/primitives/colorPicker.d.ts +38 -0
- package/fluent/primitives/colorPicker.js +174 -0
- package/fluent/primitives/colorPicker.js.map +1 -0
- package/fluent/primitives/dropdown.d.ts +8 -8
- package/fluent/primitives/dropdown.js +15 -4
- package/fluent/primitives/dropdown.js.map +1 -1
- package/fluent/primitives/input.d.ts +8 -2
- package/fluent/primitives/input.js +4 -8
- package/fluent/primitives/input.js.map +1 -1
- package/fluent/primitives/spinButton.d.ts +4 -0
- package/fluent/primitives/spinButton.js +28 -0
- package/fluent/primitives/spinButton.js.map +1 -0
- package/fluent/primitives/switch.d.ts +3 -2
- package/fluent/primitives/switch.js +8 -8
- package/fluent/primitives/switch.js.map +1 -1
- package/fluent/primitives/syncedSlider.d.ts +5 -10
- package/fluent/primitives/syncedSlider.js +8 -7
- package/fluent/primitives/syncedSlider.js.map +1 -1
- package/fluent/primitives/textarea.d.ts +4 -0
- package/fluent/primitives/textarea.js.map +1 -1
- package/lines/checkBoxLineComponent.js +2 -2
- package/lines/checkBoxLineComponent.js.map +1 -1
- package/lines/colorLineComponent.d.ts +2 -0
- package/lines/colorLineComponent.js +14 -1
- package/lines/colorLineComponent.js.map +1 -1
- package/lines/fileButtonLineComponent.d.ts +2 -0
- package/lines/fileButtonLineComponent.js +9 -1
- package/lines/fileButtonLineComponent.js.map +1 -1
- package/lines/optionsLineComponent.js +3 -3
- package/lines/optionsLineComponent.js.map +1 -1
- package/lines/sliderLineComponent.js +1 -1
- package/lines/sliderLineComponent.js.map +1 -1
- package/lines/textInputLineComponent.js +1 -10
- package/lines/textInputLineComponent.js.map +1 -1
- package/lines/vector3LineComponent.js +2 -2
- package/lines/vector3LineComponent.js.map +1 -1
- package/package.json +1 -1
- package/fluent/primitives/text.d.ts +0 -1
- package/fluent/primitives/text.js +0 -3
- package/fluent/primitives/text.js.map +0 -1
@@ -1,18 +1,37 @@
|
|
1
1
|
import type { FunctionComponent } from "react";
|
2
|
-
import type { PropertyLineProps } from "./propertyLine.js";
|
2
|
+
import type { BaseComponentProps, PropertyLineProps } from "./propertyLine.js";
|
3
3
|
import { Vector4 } from "@babylonjs/core/Maths/math.vector.js";
|
4
4
|
import type { Vector3 } from "@babylonjs/core/Maths/math.vector.js";
|
5
|
-
type
|
6
|
-
|
5
|
+
export type VectorPropertyLineProps<V extends Vector3 | Vector4> = BaseComponentProps<V> & PropertyLineProps & {
|
6
|
+
/**
|
7
|
+
* If passed, all sliders will use this for the min value
|
8
|
+
*/
|
7
9
|
min?: number;
|
10
|
+
/**
|
11
|
+
* If passed, all sliders will use this for the max value
|
12
|
+
*/
|
8
13
|
max?: number;
|
9
|
-
|
14
|
+
/**
|
15
|
+
* If passed, the UX will use the conversion functions to display/update values
|
16
|
+
*/
|
17
|
+
valueConverter?: {
|
18
|
+
/**
|
19
|
+
* Will call from(val) before displaying in the UX
|
20
|
+
*/
|
21
|
+
from: (val: number) => number;
|
22
|
+
/**
|
23
|
+
* Will call to(val) before calling onChange
|
24
|
+
*/
|
25
|
+
to: (val: number) => number;
|
26
|
+
};
|
10
27
|
};
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
export declare const
|
28
|
+
type RotationVectorPropertyLineProps = VectorPropertyLineProps<Vector3> & {
|
29
|
+
/**
|
30
|
+
* Display angles as degrees instead of radians
|
31
|
+
*/
|
32
|
+
useDegrees?: boolean;
|
33
|
+
};
|
34
|
+
export declare const RotationVectorPropertyLine: FunctionComponent<RotationVectorPropertyLineProps>;
|
35
|
+
export declare const Vector3PropertyLine: FunctionComponent<VectorPropertyLineProps<Vector3>>;
|
36
|
+
export declare const Vector4PropertyLine: FunctionComponent<VectorPropertyLineProps<Vector4>>;
|
18
37
|
export {};
|
@@ -1,19 +1,36 @@
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import { useState } from "react";
|
2
3
|
import { Body1 } from "@fluentui/react-components";
|
3
4
|
import { PropertyLine } from "./propertyLine.js";
|
4
5
|
import { SyncedSliderLine } from "./syncedSliderLine.js";
|
5
6
|
import { Vector4 } from "@babylonjs/core/Maths/math.vector.js";
|
6
|
-
|
7
|
-
const { vector, ...sliderProps } = props;
|
8
|
-
return (_jsxs(_Fragment, { children: [_jsx(SyncedSliderLine, { ...sliderProps, label: "X", propertyKey: "x", target: vector }), _jsx(SyncedSliderLine, { ...sliderProps, label: "Y", propertyKey: "y", target: vector }), _jsx(SyncedSliderLine, { ...sliderProps, label: "Z", propertyKey: "z", target: vector }), vector instanceof Vector4 && _jsx(SyncedSliderLine, { ...sliderProps, label: "W", propertyKey: "w", target: vector })] }));
|
9
|
-
};
|
7
|
+
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
10
8
|
/**
|
11
9
|
* Reusable component which renders a vector property line containing a label, vector value, and expandable XYZW values
|
12
10
|
* The expanded section contains a slider/input box for each component of the vector (x, y, z, w)
|
13
11
|
* @param props
|
14
12
|
* @returns
|
15
13
|
*/
|
16
|
-
|
17
|
-
|
14
|
+
const VectorPropertyLine = (props) => {
|
15
|
+
const converted = (val) => (props.valueConverter ? props.valueConverter.from(val) : val);
|
16
|
+
const formatted = (val) => converted(val).toFixed(2);
|
17
|
+
const [vector, setVector] = useState(props.value);
|
18
|
+
const { min, max } = props;
|
19
|
+
const onChange = (val, key) => {
|
20
|
+
const value = props.valueConverter ? props.valueConverter.to(val) : val;
|
21
|
+
const newVector = vector.clone();
|
22
|
+
newVector[key] = value; // The syncedSlider for 'w' is only rendered when vector is a Vector4, so this is safe
|
23
|
+
setVector(newVector);
|
24
|
+
props.onChange(newVector);
|
25
|
+
};
|
26
|
+
return (_jsx(PropertyLine, { ...props, expandedContent: _jsxs(_Fragment, { children: [_jsx(SyncedSliderLine, { label: "X", value: converted(vector.x), min: min, max: max, onChange: (val) => onChange(val, "x") }), _jsx(SyncedSliderLine, { label: "Y", value: converted(vector.y), min: min, max: max, onChange: (val) => onChange(val, "y") }), _jsx(SyncedSliderLine, { label: "Z", value: converted(vector.z), min: min, max: max, onChange: (val) => onChange(val, "z") }), vector instanceof Vector4 && _jsx(SyncedSliderLine, { label: "W", value: vector.w, min: min, max: max, onChange: (val) => onChange(val, "w") })] }), children: _jsx(Body1, { children: `X: ${formatted(props.value.x)} | Y: ${formatted(props.value.y)} | Z: ${formatted(props.value.z)}${props.value instanceof Vector4 ? ` | W: ${formatted(props.value.w)}` : ""}` }) }));
|
27
|
+
};
|
28
|
+
const ToDegreesConverter = { from: Tools.ToDegrees, to: Tools.ToRadians };
|
29
|
+
export const RotationVectorPropertyLine = (props) => {
|
30
|
+
const min = props.useDegrees ? 0 : undefined;
|
31
|
+
const max = props.useDegrees ? 360 : undefined;
|
32
|
+
return _jsx(Vector3PropertyLine, { ...props, valueConverter: props.useDegrees ? ToDegreesConverter : undefined, min: min, max: max });
|
18
33
|
};
|
34
|
+
export const Vector3PropertyLine = VectorPropertyLine;
|
35
|
+
export const Vector4PropertyLine = VectorPropertyLine;
|
19
36
|
//# sourceMappingURL=vectorPropertyLine.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"vectorPropertyLine.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/hoc/vectorPropertyLine.tsx"],"names":[],"mappings":";
|
1
|
+
{"version":3,"file":"vectorPropertyLine.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/hoc/vectorPropertyLine.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\r\nimport type { FunctionComponent } from \"react\";\r\n\r\nimport { Body1 } from \"@fluentui/react-components\";\r\nimport { PropertyLine } from \"./propertyLine\";\r\nimport type { BaseComponentProps, PropertyLineProps } from \"./propertyLine\";\r\n\r\nimport { SyncedSliderLine } from \"./syncedSliderLine\";\r\n\r\nimport { Vector4 } from \"core/Maths/math.vector\";\r\nimport type { Vector3 } from \"core/Maths/math.vector\";\r\nimport { Tools } from \"core/Misc/tools\";\r\n\r\nexport type VectorPropertyLineProps<V extends Vector3 | Vector4> = BaseComponentProps<V> &\r\n PropertyLineProps & {\r\n /**\r\n * If passed, all sliders will use this for the min value\r\n */\r\n min?: number;\r\n /**\r\n * If passed, all sliders will use this for the max value\r\n */\r\n max?: number;\r\n /**\r\n * If passed, the UX will use the conversion functions to display/update values\r\n */\r\n valueConverter?: {\r\n /**\r\n * Will call from(val) before displaying in the UX\r\n */\r\n from: (val: number) => number;\r\n /**\r\n * Will call to(val) before calling onChange\r\n */\r\n to: (val: number) => number;\r\n };\r\n };\r\n\r\n/**\r\n * Reusable component which renders a vector property line containing a label, vector value, and expandable XYZW values\r\n * The expanded section contains a slider/input box for each component of the vector (x, y, z, w)\r\n * @param props\r\n * @returns\r\n */\r\nconst VectorPropertyLine: FunctionComponent<VectorPropertyLineProps<Vector3 | Vector4>> = (props) => {\r\n const converted = (val: number) => (props.valueConverter ? props.valueConverter.from(val) : val);\r\n const formatted = (val: number) => converted(val).toFixed(2);\r\n\r\n const [vector, setVector] = useState(props.value);\r\n const { min, max } = props;\r\n\r\n const onChange = (val: number, key: \"x\" | \"y\" | \"z\" | \"w\") => {\r\n const value = props.valueConverter ? props.valueConverter.to(val) : val;\r\n const newVector = vector.clone();\r\n (newVector as Vector4)[key] = value; // The syncedSlider for 'w' is only rendered when vector is a Vector4, so this is safe\r\n\r\n setVector(newVector);\r\n props.onChange(newVector);\r\n };\r\n\r\n return (\r\n <PropertyLine\r\n {...props}\r\n expandedContent={\r\n <>\r\n <SyncedSliderLine label=\"X\" value={converted(vector.x)} min={min} max={max} onChange={(val) => onChange(val, \"x\")} />\r\n <SyncedSliderLine label=\"Y\" value={converted(vector.y)} min={min} max={max} onChange={(val) => onChange(val, \"y\")} />\r\n <SyncedSliderLine label=\"Z\" value={converted(vector.z)} min={min} max={max} onChange={(val) => onChange(val, \"z\")} />\r\n {vector instanceof Vector4 && <SyncedSliderLine label=\"W\" value={vector.w} min={min} max={max} onChange={(val) => onChange(val, \"w\")} />}\r\n </>\r\n }\r\n >\r\n <Body1>{`X: ${formatted(props.value.x)} | Y: ${formatted(props.value.y)} | Z: ${formatted(props.value.z)}${props.value instanceof Vector4 ? ` | W: ${formatted(props.value.w)}` : \"\"}`}</Body1>\r\n </PropertyLine>\r\n );\r\n};\r\n\r\ntype RotationVectorPropertyLineProps = VectorPropertyLineProps<Vector3> & {\r\n /**\r\n * Display angles as degrees instead of radians\r\n */\r\n useDegrees?: boolean;\r\n};\r\n\r\nconst ToDegreesConverter = { from: Tools.ToDegrees, to: Tools.ToRadians };\r\nexport const RotationVectorPropertyLine: FunctionComponent<RotationVectorPropertyLineProps> = (props) => {\r\n const min = props.useDegrees ? 0 : undefined;\r\n const max = props.useDegrees ? 360 : undefined;\r\n return <Vector3PropertyLine {...props} valueConverter={props.useDegrees ? ToDegreesConverter : undefined} min={min} max={max} />;\r\n};\r\n\r\nexport const Vector3PropertyLine = VectorPropertyLine as FunctionComponent<VectorPropertyLineProps<Vector3>>;\r\nexport const Vector4PropertyLine = VectorPropertyLine as FunctionComponent<VectorPropertyLineProps<Vector4>>;\r\n"]}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
import type { FunctionComponent, PropsWithChildren } from "react";
|
2
|
+
export type AccordionSectionProps = {
|
3
|
+
title: string;
|
4
|
+
};
|
5
|
+
export declare const AccordionSection: FunctionComponent<PropsWithChildren<AccordionSectionProps>>;
|
6
|
+
export declare const Accordion: FunctionComponent<PropsWithChildren>;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import { Children, isValidElement } from "react";
|
3
|
+
import { Accordion as FluentAccordion, AccordionItem, AccordionHeader, AccordionPanel, Subtitle1, makeStyles, tokens } from "@fluentui/react-components";
|
4
|
+
const useStyles = makeStyles({
|
5
|
+
accordion: {
|
6
|
+
overflowY: "auto",
|
7
|
+
paddingBottom: tokens.spacingVerticalM,
|
8
|
+
display: "flex",
|
9
|
+
flexDirection: "column",
|
10
|
+
rowGap: tokens.spacingVerticalM,
|
11
|
+
},
|
12
|
+
panelDiv: {
|
13
|
+
display: "flex",
|
14
|
+
flexDirection: "column",
|
15
|
+
overflow: "hidden",
|
16
|
+
},
|
17
|
+
});
|
18
|
+
export const AccordionSection = (props) => {
|
19
|
+
const classes = useStyles();
|
20
|
+
return _jsx("div", { className: classes.panelDiv, children: props.children });
|
21
|
+
};
|
22
|
+
export const Accordion = (props) => {
|
23
|
+
const classes = useStyles();
|
24
|
+
const { children, ...rest } = props;
|
25
|
+
return (_jsx(FluentAccordion, { className: classes.accordion, collapsible: true, multiple: true, defaultOpenItems: Array.from({ length: Children.count(children) }, (_, index) => index), ...rest, children: Children.map(children, (child, index) => {
|
26
|
+
if (isValidElement(child)) {
|
27
|
+
return (_jsxs(AccordionItem, { value: index, children: [_jsx(AccordionHeader, { expandIconPosition: "end", children: _jsx(Subtitle1, { children: child.props.title }) }), _jsx(AccordionPanel, { children: _jsx("div", { className: classes.panelDiv, children: child }) })] }, child.props.title));
|
28
|
+
}
|
29
|
+
return null;
|
30
|
+
}) }));
|
31
|
+
};
|
32
|
+
//# sourceMappingURL=accordion.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/accordion.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEjD,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzJ,MAAM,SAAS,GAAG,UAAU,CAAC;IACzB,SAAS,EAAE;QACP,SAAS,EAAE,MAAM;QACjB,aAAa,EAAE,MAAM,CAAC,gBAAgB;QACtC,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,MAAM,EAAE,MAAM,CAAC,gBAAgB;KAClC;IACD,QAAQ,EAAE;QACN,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,QAAQ,EAAE,QAAQ;KACrB;CACJ,CAAC,CAAC;AAMH,MAAM,CAAC,MAAM,gBAAgB,GAAgE,CAAC,KAAK,EAAE,EAAE;IACnG,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAE5B,OAAO,cAAK,SAAS,EAAE,OAAO,CAAC,QAAQ,YAAG,KAAK,CAAC,QAAQ,GAAO,CAAC;AACpE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAyC,CAAC,KAAK,EAAE,EAAE;IACrE,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAE5B,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IAEpC,OAAO,CACH,KAAC,eAAe,IAAC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,WAAW,QAAC,QAAQ,QAAC,gBAAgB,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAM,IAAI,YAChK,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACrC,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CACH,MAAC,aAAa,IAAyB,KAAK,EAAE,KAAK,aAC/C,KAAC,eAAe,IAAC,kBAAkB,EAAC,KAAK,YACrC,KAAC,SAAS,cAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAa,GAC5B,EAClB,KAAC,cAAc,cACX,cAAK,SAAS,EAAE,OAAO,CAAC,QAAQ,YAAG,KAAK,GAAO,GAClC,KAND,KAAK,CAAC,KAAK,CAAC,KAAK,CAOrB,CACnB,CAAC;YACN,CAAC;YACD,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC,GACY,CACrB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type { FunctionComponent, PropsWithChildren } from \"react\";\r\n\r\nimport { Children, isValidElement } from \"react\";\r\n\r\nimport { Accordion as FluentAccordion, AccordionItem, AccordionHeader, AccordionPanel, Subtitle1, makeStyles, tokens } from \"@fluentui/react-components\";\r\n\r\nconst useStyles = makeStyles({\r\n accordion: {\r\n overflowY: \"auto\",\r\n paddingBottom: tokens.spacingVerticalM,\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n rowGap: tokens.spacingVerticalM,\r\n },\r\n panelDiv: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n overflow: \"hidden\",\r\n },\r\n});\r\n\r\nexport type AccordionSectionProps = {\r\n title: string;\r\n};\r\n\r\nexport const AccordionSection: FunctionComponent<PropsWithChildren<AccordionSectionProps>> = (props) => {\r\n const classes = useStyles();\r\n\r\n return <div className={classes.panelDiv}>{props.children}</div>;\r\n};\r\n\r\nexport const Accordion: FunctionComponent<PropsWithChildren> = (props) => {\r\n const classes = useStyles();\r\n\r\n const { children, ...rest } = props;\r\n\r\n return (\r\n <FluentAccordion className={classes.accordion} collapsible multiple defaultOpenItems={Array.from({ length: Children.count(children) }, (_, index) => index)} {...rest}>\r\n {Children.map(children, (child, index) => {\r\n if (isValidElement(child)) {\r\n return (\r\n <AccordionItem key={child.props.title} value={index}>\r\n <AccordionHeader expandIconPosition=\"end\">\r\n <Subtitle1>{child.props.title}</Subtitle1>\r\n </AccordionHeader>\r\n <AccordionPanel>\r\n <div className={classes.panelDiv}>{child}</div>\r\n </AccordionPanel>\r\n </AccordionItem>\r\n );\r\n }\r\n return null;\r\n })}\r\n </FluentAccordion>\r\n );\r\n};\r\n"]}
|
@@ -1,5 +1,6 @@
|
|
1
|
-
import type { CheckboxProps } from "@fluentui/react-components";
|
2
1
|
import type { FunctionComponent } from "react";
|
2
|
+
import type { BaseComponentProps } from "../hoc/propertyLine.js";
|
3
|
+
export type CheckboxProps = BaseComponentProps<boolean>;
|
3
4
|
/**
|
4
5
|
* This is a primitive fluent checkbox that can both read and write checked state
|
5
6
|
* @param props
|
@@ -7,16 +7,16 @@ import { useEffect, useState } from "react";
|
|
7
7
|
* @returns Checkbox component
|
8
8
|
*/
|
9
9
|
export const Checkbox = (props) => {
|
10
|
-
const [checked, setChecked] = useState(() => props.
|
10
|
+
const [checked, setChecked] = useState(() => props.value ?? false);
|
11
11
|
useEffect(() => {
|
12
|
-
if (props.
|
13
|
-
setChecked(props.
|
12
|
+
if (props.value != undefined) {
|
13
|
+
setChecked(props.value); // Update local state when props.checked changes
|
14
14
|
}
|
15
|
-
}, [props.
|
16
|
-
const onChange = (ev,
|
17
|
-
props.onChange
|
15
|
+
}, [props.value]);
|
16
|
+
const onChange = (ev, _) => {
|
17
|
+
props.onChange(ev.target.checked);
|
18
18
|
setChecked(ev.target.checked);
|
19
19
|
};
|
20
|
-
return _jsx(FluentCheckbox, {
|
20
|
+
return _jsx(FluentCheckbox, { checked: checked, onChange: onChange, disabled: props.disabled });
|
21
21
|
};
|
22
22
|
//# sourceMappingURL=checkbox.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"checkbox.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/checkbox.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
1
|
+
{"version":3,"file":"checkbox.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/checkbox.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAI5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAqC,CAAC,KAAK,EAAE,EAAE;IAChE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC;IAEnE,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,KAAK,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC;YAC3B,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,gDAAgD;QAC7E,CAAC;IACL,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAElB,MAAM,QAAQ,GAAG,CAAC,EAAiC,EAAE,CAAuB,EAAE,EAAE;QAC5E,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC,CAAC;IAEF,OAAO,KAAC,cAAc,IAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAI,CAAC;AAC9F,CAAC,CAAC","sourcesContent":["// eslint-disable-next-line import/no-internal-modules\r\n\r\nimport type { CheckboxOnChangeData } from \"@fluentui/react-components\";\r\nimport type { ChangeEvent, FunctionComponent } from \"react\";\r\n\r\nimport { Checkbox as FluentCheckbox } from \"@fluentui/react-components\";\r\nimport { useEffect, useState } from \"react\";\r\nimport type { BaseComponentProps } from \"../hoc/propertyLine\";\r\n\r\nexport type CheckboxProps = BaseComponentProps<boolean>;\r\n/**\r\n * This is a primitive fluent checkbox that can both read and write checked state\r\n * @param props\r\n * @returns Checkbox component\r\n */\r\nexport const Checkbox: FunctionComponent<CheckboxProps> = (props) => {\r\n const [checked, setChecked] = useState(() => props.value ?? false);\r\n\r\n useEffect(() => {\r\n if (props.value != undefined) {\r\n setChecked(props.value); // Update local state when props.checked changes\r\n }\r\n }, [props.value]);\r\n\r\n const onChange = (ev: ChangeEvent<HTMLInputElement>, _: CheckboxOnChangeData) => {\r\n props.onChange(ev.target.checked);\r\n setChecked(ev.target.checked);\r\n };\r\n\r\n return <FluentCheckbox checked={checked} onChange={onChange} disabled={props.disabled} />;\r\n};\r\n"]}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import type { FunctionComponent } from "react";
|
2
|
+
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color.js";
|
3
|
+
import type { BaseComponentProps } from "../hoc/propertyLine.js";
|
4
|
+
export type ColorPickerProps<C extends Color3 | Color4> = {
|
5
|
+
isLinearMode?: boolean;
|
6
|
+
} & BaseComponentProps<C>;
|
7
|
+
export declare const ColorPickerPopup: FunctionComponent<ColorPickerProps<Color3 | Color4>>;
|
8
|
+
type HsvKey = "h" | "s" | "v";
|
9
|
+
export type InputHexProps = BaseComponentProps<Color3 | Color4> & {
|
10
|
+
label?: string;
|
11
|
+
linearHex?: boolean;
|
12
|
+
isLinearMode?: boolean;
|
13
|
+
};
|
14
|
+
/**
|
15
|
+
* Component which displays the passed in color's HEX value, either in linearSpace (if linearHex is true) or in gamma space
|
16
|
+
* When the hex color is changed by user, component calculates the new Color3/4 value and calls onChange
|
17
|
+
*
|
18
|
+
* Component uses the isLinearMode boolean to display an informative label regarding linear / gamma space
|
19
|
+
* @param props - The properties for the InputHexField component.
|
20
|
+
* @returns
|
21
|
+
*/
|
22
|
+
export declare const InputHexField: FunctionComponent<InputHexProps>;
|
23
|
+
type InputHsvFieldProps = {
|
24
|
+
color: Color3 | Color4;
|
25
|
+
label: string;
|
26
|
+
hsvKey: HsvKey;
|
27
|
+
onChange: (color: Color3 | Color4) => void;
|
28
|
+
max: number;
|
29
|
+
scale?: number;
|
30
|
+
};
|
31
|
+
/**
|
32
|
+
* In the HSV (Hue, Saturation, Value) color model, Hue (H) ranges from 0 to 360 degrees, representing the color's position on the color wheel.
|
33
|
+
* Saturation (S) ranges from 0 to 100%, indicating the intensity or purity of the color, with 0 being shades of gray and 100 being a fully saturated color.
|
34
|
+
* Value (V) ranges from 0 to 100%, representing the brightness of the color, with 0 being black and 100 being the brightest.
|
35
|
+
* @param props - The properties for the InputHsvField component.
|
36
|
+
*/
|
37
|
+
export declare const InputHsvField: FunctionComponent<InputHsvFieldProps>;
|
38
|
+
export {};
|
@@ -0,0 +1,174 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
2
|
+
/* eslint-disable jsdoc/require-returns */
|
3
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
4
|
+
import { useState, useEffect, useCallback } from "react";
|
5
|
+
import { Input, Label, SpinButton, useId, ColorPicker, ColorSlider, ColorArea, AlphaSlider, InfoLabel, Link, makeStyles, Popover, PopoverSurface, PopoverTrigger, tokens, Body1Strong, } from "@fluentui/react-components";
|
6
|
+
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color.js";
|
7
|
+
const useColorPickerStyles = makeStyles({
|
8
|
+
colorPickerContainer: {
|
9
|
+
width: "300px",
|
10
|
+
display: "flex",
|
11
|
+
flexDirection: "column",
|
12
|
+
gap: tokens.spacingVerticalMNudge, // 10px
|
13
|
+
overflow: "visible",
|
14
|
+
},
|
15
|
+
triggerColor: {
|
16
|
+
width: "50px",
|
17
|
+
height: tokens.lineHeightBase100,
|
18
|
+
borderRadius: tokens.borderRadiusMedium,
|
19
|
+
cursor: "pointer", // Show pointer on hover
|
20
|
+
border: `${tokens.spacingVerticalXXS} solid ${tokens.colorNeutralShadowKeyLighter}`,
|
21
|
+
"@media (forced-colors: active)": {
|
22
|
+
forcedColorAdjust: "none", // ensures element maintains color in high contrast mode
|
23
|
+
},
|
24
|
+
},
|
25
|
+
previewColor: {
|
26
|
+
width: "50px",
|
27
|
+
height: "50px",
|
28
|
+
borderRadius: tokens.borderRadiusMedium,
|
29
|
+
border: `${tokens.spacingVerticalXXS} solid ${tokens.colorNeutralShadowKeyLighter}`,
|
30
|
+
"@media (forced-colors: active)": {
|
31
|
+
forcedColorAdjust: "none", // ensures elmement maintains color in high constrast mode
|
32
|
+
},
|
33
|
+
},
|
34
|
+
row: {
|
35
|
+
display: "flex",
|
36
|
+
flexDirection: "row",
|
37
|
+
gap: tokens.spacingVerticalM, // 12px
|
38
|
+
alignItems: "center",
|
39
|
+
},
|
40
|
+
colorFieldWrapper: {
|
41
|
+
display: "flex",
|
42
|
+
flexDirection: "column",
|
43
|
+
gap: tokens.spacingVerticalSNudge, // 6px
|
44
|
+
},
|
45
|
+
input: {
|
46
|
+
width: "80px",
|
47
|
+
},
|
48
|
+
spinButton: {
|
49
|
+
minWidth: "60px",
|
50
|
+
},
|
51
|
+
container: {
|
52
|
+
display: "flex",
|
53
|
+
flexDirection: "column",
|
54
|
+
gap: tokens.spacingVerticalL, // 16px
|
55
|
+
},
|
56
|
+
});
|
57
|
+
export const ColorPickerPopup = (props) => {
|
58
|
+
const classes = useColorPickerStyles();
|
59
|
+
const [color, setColor] = useState(props.value);
|
60
|
+
const [popoverOpen, setPopoverOpen] = useState(false);
|
61
|
+
useEffect(() => {
|
62
|
+
props.onChange(color); // Ensures the parent is notified when color changes from within colorPicker
|
63
|
+
}, [color]);
|
64
|
+
useEffect(() => {
|
65
|
+
setColor(props.value); // Ensures the trigger color updates when props.value changes
|
66
|
+
}, [props.value]);
|
67
|
+
const handleChange = (_, data) => {
|
68
|
+
let color = Color3.FromHSV(data.color.h, data.color.s, data.color.v);
|
69
|
+
if (props.value instanceof Color4) {
|
70
|
+
color = Color4.FromColor3(color, data.color.a ?? 1);
|
71
|
+
}
|
72
|
+
setColor(color);
|
73
|
+
};
|
74
|
+
return (_jsxs(Popover, { positioning: {
|
75
|
+
align: "start",
|
76
|
+
overflowBoundary: document.body,
|
77
|
+
autoSize: true,
|
78
|
+
}, open: popoverOpen, trapFocus: true, onOpenChange: (_, data) => setPopoverOpen(data.open), children: [_jsx(PopoverTrigger, { disableButtonEnhancement: true, children: _jsx("div", { className: classes.triggerColor, style: { backgroundColor: color.toHexString() } }) }), _jsx(PopoverSurface, { children: _jsxs("div", { className: classes.colorPickerContainer, children: [_jsxs(ColorPicker, { color: rgbaToHsv(color), onColorChange: handleChange, 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, { label: "Gamma Hex", value: color, isLinearMode: props.isLinearMode, onChange: setColor }), _jsx(InputHexField, { label: "Linear Hex", linearHex: true, isLinearMode: props.isLinearMode, value: color, onChange: setColor })] }), _jsxs("div", { className: classes.row, children: [_jsx(InputRgbField, { label: "Red", color: color, rgbKey: "r", onChange: setColor }), _jsx(InputRgbField, { label: "Green", color: color, rgbKey: "g", onChange: setColor }), _jsx(InputRgbField, { label: "Blue", color: color, rgbKey: "b", onChange: setColor }), _jsx(InputAlphaField, { color: color, onChange: setColor })] }), _jsxs("div", { className: classes.row, children: [_jsx(InputHsvField, { label: "Hue", color: color, hsvKey: "h", max: 360, onChange: setColor }), _jsx(InputHsvField, { label: "Saturation", color: color, hsvKey: "s", max: 100, scale: 100, onChange: setColor }), _jsx(InputHsvField, { label: "Value", color: color, hsvKey: "v", max: 100, scale: 100, onChange: setColor })] })] })] }) })] }));
|
79
|
+
};
|
80
|
+
/**
|
81
|
+
* Component which displays the passed in color's HEX value, either in linearSpace (if linearHex is true) or in gamma space
|
82
|
+
* When the hex color is changed by user, component calculates the new Color3/4 value and calls onChange
|
83
|
+
*
|
84
|
+
* Component uses the isLinearMode boolean to display an informative label regarding linear / gamma space
|
85
|
+
* @param props - The properties for the InputHexField component.
|
86
|
+
* @returns
|
87
|
+
*/
|
88
|
+
export const InputHexField = (props) => {
|
89
|
+
const id = useId("hex-input");
|
90
|
+
const styles = useColorPickerStyles();
|
91
|
+
const { label, value, onChange, linearHex, isLinearMode } = props;
|
92
|
+
const handleChange = (e, _) => {
|
93
|
+
// If linearHint (aka PBR material, ensure the other values are displayed in gamma even if linear hex changes)
|
94
|
+
const value = e.target.value;
|
95
|
+
if (value != "" && /^[0-9A-Fa-f]+$/g.test(value) == false) {
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
onChange(Color3.FromHexString(value).toGammaSpace());
|
99
|
+
};
|
100
|
+
return (_jsxs("div", { className: styles.colorFieldWrapper, children: [props.linearHex ? (_jsx(InfoLabel, { htmlFor: id, info: !isLinearMode ? (_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 " })) : (_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! " })] })), children: label })) : (_jsx(Label, { htmlFor: id, children: label })), _jsx(Input, { disabled: linearHex ? !isLinearMode : false, className: styles.input, value: linearHex ? value.toLinearSpace().toHexString() : value.toHexString(), id: id, onChange: handleChange })] }));
|
101
|
+
};
|
102
|
+
const InputRgbField = (props) => {
|
103
|
+
const { color, onChange, label, rgbKey } = props;
|
104
|
+
const id = useId(`${label.toLowerCase()}-input`);
|
105
|
+
const classes = useColorPickerStyles();
|
106
|
+
const handleChange = useCallback((_, data) => {
|
107
|
+
const val = data.value ?? parseFloat(data.displayValue ?? "");
|
108
|
+
if (val === null || Number.isNaN(val) || !NUMBER_REGEX.test(val.toString())) {
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
const newColor = color.clone();
|
112
|
+
newColor[rgbKey] = val / 255.0; // Convert to 0-1 range
|
113
|
+
onChange(newColor);
|
114
|
+
}, [color]);
|
115
|
+
return (_jsxs("div", { className: classes.colorFieldWrapper, children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(SpinButton, { className: classes.spinButton, min: 0, max: 255, value: color[rgbKey] * 255.0, step: 1, id: id, onChange: handleChange, name: rgbKey })] }));
|
116
|
+
};
|
117
|
+
/**
|
118
|
+
* In the HSV (Hue, Saturation, Value) color model, Hue (H) ranges from 0 to 360 degrees, representing the color's position on the color wheel.
|
119
|
+
* Saturation (S) ranges from 0 to 100%, indicating the intensity or purity of the color, with 0 being shades of gray and 100 being a fully saturated color.
|
120
|
+
* Value (V) ranges from 0 to 100%, representing the brightness of the color, with 0 being black and 100 being the brightest.
|
121
|
+
* @param props - The properties for the InputHsvField component.
|
122
|
+
*/
|
123
|
+
export const InputHsvField = (props) => {
|
124
|
+
const { color, label, hsvKey, max, scale = 1 } = props;
|
125
|
+
const id = useId(`${label.toLowerCase()}-input`);
|
126
|
+
const classes = useColorPickerStyles();
|
127
|
+
const handleChange = useCallback((_, data) => {
|
128
|
+
const val = data.value ?? parseFloat(data.displayValue ?? "");
|
129
|
+
if (val === null || Number.isNaN(val) || !NUMBER_REGEX.test(val.toString())) {
|
130
|
+
return;
|
131
|
+
}
|
132
|
+
// Convert current color to HSV, update the new hsv value, then call onChange prop
|
133
|
+
const hsv = rgbaToHsv(color);
|
134
|
+
hsv[hsvKey] = val / scale;
|
135
|
+
let newColor = Color3.FromHSV(hsv.h, hsv.s, hsv.v);
|
136
|
+
if (color instanceof Color4) {
|
137
|
+
newColor = Color4.FromColor3(newColor, color.a ?? 1);
|
138
|
+
}
|
139
|
+
props.onChange(newColor);
|
140
|
+
}, [color]);
|
141
|
+
return (_jsxs("div", { className: classes.colorFieldWrapper, children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(SpinButton, { className: classes.spinButton, min: 0, max: max, value: rgbaToHsv(color)[hsvKey] * scale, step: 1, id: id, onChange: handleChange, name: hsvKey })] }));
|
142
|
+
};
|
143
|
+
/**
|
144
|
+
* 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).
|
145
|
+
* @param props
|
146
|
+
* @returns
|
147
|
+
*/
|
148
|
+
const InputAlphaField = (props) => {
|
149
|
+
const classes = useColorPickerStyles();
|
150
|
+
const id = useId("alpha-input");
|
151
|
+
const { color } = props;
|
152
|
+
const onChange = (_, data) => {
|
153
|
+
const value = data.value ?? parseFloat(data.displayValue ?? "");
|
154
|
+
if (Number.isNaN(value) || value < 0 || value > 1) {
|
155
|
+
return;
|
156
|
+
}
|
157
|
+
if (color instanceof Color4) {
|
158
|
+
const newColor = color.clone();
|
159
|
+
newColor.a = value;
|
160
|
+
return newColor;
|
161
|
+
}
|
162
|
+
else {
|
163
|
+
return Color4.FromColor3(color, value);
|
164
|
+
}
|
165
|
+
};
|
166
|
+
return (_jsxs("div", { className: classes.colorFieldWrapper, children: [_jsxs("div", { className: classes.row, children: [_jsx(Label, { htmlFor: id, children: "Alpha" }), color instanceof Color3 && (_jsx(InfoLabel, { htmlFor: id, info: _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 material's alpha property directly, either in code via material.alpha OR via inspector's transparency section." }) }))] }), _jsx(SpinButton, { disabled: color instanceof Color3, min: 0, max: 1, className: classes.spinButton, value: color instanceof Color3 ? 1 : color.a, step: 0.01, onChange: onChange, id: id })] }));
|
167
|
+
};
|
168
|
+
const NUMBER_REGEX = /^\d+$/;
|
169
|
+
function rgbaToHsv(color) {
|
170
|
+
const c = new Color3(color.r, color.g, color.b);
|
171
|
+
const hsv = c.toHSV();
|
172
|
+
return { h: hsv.r, s: hsv.g, v: hsv.b, a: color.a };
|
173
|
+
}
|
174
|
+
//# sourceMappingURL=colorPicker.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"colorPicker.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/colorPicker.tsx"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable jsdoc/require-returns */\r\n/* eslint-disable @typescript-eslint/naming-convention */\r\nimport { useState, useEffect, useCallback } from \"react\";\r\nimport type { FunctionComponent, ChangeEvent } from \"react\";\r\nimport {\r\n Input,\r\n Label,\r\n SpinButton,\r\n useId,\r\n ColorPicker,\r\n ColorSlider,\r\n ColorArea,\r\n AlphaSlider,\r\n InfoLabel,\r\n Link,\r\n makeStyles,\r\n Popover,\r\n PopoverSurface,\r\n PopoverTrigger,\r\n tokens,\r\n Body1Strong,\r\n} from \"@fluentui/react-components\";\r\nimport type { SpinButtonChangeEvent, SpinButtonOnChangeData, ColorPickerProps as FluentColorPickerProps, InputOnChangeData } from \"@fluentui/react-components\";\r\nimport { Color3, Color4 } from \"core/Maths/math.color\";\r\nimport type { BaseComponentProps } from \"../hoc/propertyLine\";\r\n\r\nconst useColorPickerStyles = makeStyles({\r\n colorPickerContainer: {\r\n width: \"300px\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: tokens.spacingVerticalMNudge, // 10px\r\n overflow: \"visible\",\r\n },\r\n triggerColor: {\r\n width: \"50px\",\r\n height: tokens.lineHeightBase100,\r\n borderRadius: tokens.borderRadiusMedium,\r\n cursor: \"pointer\", // Show pointer on hover\r\n border: `${tokens.spacingVerticalXXS} solid ${tokens.colorNeutralShadowKeyLighter}`,\r\n \"@media (forced-colors: active)\": {\r\n forcedColorAdjust: \"none\", // ensures element maintains color in high contrast mode\r\n },\r\n },\r\n previewColor: {\r\n width: \"50px\",\r\n height: \"50px\",\r\n borderRadius: tokens.borderRadiusMedium,\r\n border: `${tokens.spacingVerticalXXS} solid ${tokens.colorNeutralShadowKeyLighter}`,\r\n \"@media (forced-colors: active)\": {\r\n forcedColorAdjust: \"none\", // ensures elmement maintains color in high constrast mode\r\n },\r\n },\r\n row: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n gap: tokens.spacingVerticalM, // 12px\r\n alignItems: \"center\",\r\n },\r\n colorFieldWrapper: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: tokens.spacingVerticalSNudge, // 6px\r\n },\r\n input: {\r\n width: \"80px\",\r\n },\r\n spinButton: {\r\n minWidth: \"60px\",\r\n },\r\n container: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: tokens.spacingVerticalL, // 16px\r\n },\r\n});\r\n\r\nexport type ColorPickerProps<C extends Color3 | Color4> = {\r\n isLinearMode?: boolean;\r\n} & BaseComponentProps<C>;\r\n\r\nexport const ColorPickerPopup: FunctionComponent<ColorPickerProps<Color3 | Color4>> = (props) => {\r\n const classes = useColorPickerStyles();\r\n const [color, setColor] = useState(props.value);\r\n\r\n const [popoverOpen, setPopoverOpen] = useState(false);\r\n\r\n useEffect(() => {\r\n props.onChange(color); // Ensures the parent is notified when color changes from within colorPicker\r\n }, [color]);\r\n\r\n useEffect(() => {\r\n setColor(props.value); // Ensures the trigger color updates when props.value changes\r\n }, [props.value]);\r\n\r\n const handleChange: FluentColorPickerProps[\"onColorChange\"] = (_, data) => {\r\n let color: Color3 | Color4 = Color3.FromHSV(data.color.h, data.color.s, data.color.v);\r\n if (props.value instanceof Color4) {\r\n color = Color4.FromColor3(color, data.color.a ?? 1);\r\n }\r\n setColor(color);\r\n };\r\n\r\n return (\r\n <Popover\r\n positioning={{\r\n align: \"start\",\r\n overflowBoundary: document.body,\r\n autoSize: true,\r\n }}\r\n open={popoverOpen}\r\n trapFocus\r\n onOpenChange={(_, data) => setPopoverOpen(data.open)}\r\n >\r\n <PopoverTrigger disableButtonEnhancement>\r\n <div className={classes.triggerColor} style={{ backgroundColor: color.toHexString() }} />\r\n </PopoverTrigger>\r\n\r\n <PopoverSurface>\r\n <div className={classes.colorPickerContainer}>\r\n <ColorPicker color={rgbaToHsv(color)} onColorChange={handleChange}>\r\n <ColorArea inputX={{ \"aria-label\": \"Saturation\" }} inputY={{ \"aria-label\": \"Brightness\" }} />\r\n <ColorSlider aria-label=\"Hue\" />\r\n {color instanceof Color4 && <AlphaSlider aria-label=\"Alpha\" />}\r\n </ColorPicker>\r\n <div className={classes.container}>\r\n {/* Top Row: Preview, Gamma Hex, Linear Hex */}\r\n <div className={classes.row}>\r\n <div className={classes.previewColor} style={{ backgroundColor: color.toHexString() }} />\r\n <InputHexField label=\"Gamma Hex\" value={color} isLinearMode={props.isLinearMode} onChange={setColor} />\r\n <InputHexField label=\"Linear Hex\" linearHex={true} isLinearMode={props.isLinearMode} value={color} onChange={setColor} />\r\n </div>\r\n\r\n {/* Middle Row: Red, Green, Blue, Alpha */}\r\n <div className={classes.row}>\r\n <InputRgbField label=\"Red\" color={color} rgbKey=\"r\" onChange={setColor} />\r\n <InputRgbField label=\"Green\" color={color} rgbKey=\"g\" onChange={setColor} />\r\n <InputRgbField label=\"Blue\" color={color} rgbKey=\"b\" onChange={setColor} />\r\n <InputAlphaField color={color} onChange={setColor} />\r\n </div>\r\n\r\n {/* Bottom Row: Hue, Saturation, Value */}\r\n <div className={classes.row}>\r\n <InputHsvField label=\"Hue\" color={color} hsvKey=\"h\" max={360} onChange={setColor} />\r\n <InputHsvField label=\"Saturation\" color={color} hsvKey=\"s\" max={100} scale={100} onChange={setColor} />\r\n <InputHsvField label=\"Value\" color={color} hsvKey=\"v\" max={100} scale={100} onChange={setColor} />\r\n </div>\r\n </div>\r\n </div>\r\n </PopoverSurface>\r\n </Popover>\r\n );\r\n};\r\n\r\ntype HsvKey = \"h\" | \"s\" | \"v\";\r\nexport type InputHexProps = BaseComponentProps<Color3 | Color4> & {\r\n label?: string;\r\n linearHex?: boolean;\r\n isLinearMode?: boolean;\r\n};\r\n/**\r\n * Component which displays the passed in color's HEX value, either in linearSpace (if linearHex is true) or in gamma space\r\n * When the hex color is changed by user, component calculates the new Color3/4 value and calls onChange\r\n *\r\n * Component uses the isLinearMode boolean to display an informative label regarding linear / gamma space\r\n * @param props - The properties for the InputHexField component.\r\n * @returns\r\n */\r\nexport const InputHexField: FunctionComponent<InputHexProps> = (props) => {\r\n const id = useId(\"hex-input\");\r\n const styles = useColorPickerStyles();\r\n const { label, value, onChange, linearHex, isLinearMode } = props;\r\n\r\n const handleChange = (e: ChangeEvent<HTMLInputElement>, _: InputOnChangeData) => {\r\n // If linearHint (aka PBR material, ensure the other values are displayed in gamma even if linear hex changes)\r\n const value = e.target.value;\r\n if (value != \"\" && /^[0-9A-Fa-f]+$/g.test(value) == false) {\r\n return;\r\n }\r\n onChange(Color3.FromHexString(value).toGammaSpace());\r\n };\r\n return (\r\n <div className={styles.colorFieldWrapper}>\r\n {props.linearHex ? (\r\n <InfoLabel\r\n htmlFor={id}\r\n info={\r\n !isLinearMode ? (\r\n <> This color picker is attached to an entity whose color is stored in gamma space, so we are showing linear hex in disabled view </>\r\n ) : (\r\n <>\r\n 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\r\n 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\r\n space so that the color chosen here will match the color seen in your entity.\r\n <br />\r\n If you want to copy/paste the HEX into your code, you can either use\r\n <Body1Strong>Color3.FromHexString(LINEAR_HEX)</Body1Strong>\r\n <br />\r\n or\r\n <br />\r\n <Body1Strong>Color3.FromHexString(GAMMA_HEX).toLinearSpace()</Body1Strong>\r\n <br />\r\n <br />\r\n <Link href=\"https://doc.babylonjs.com/preparingArtForBabylon/controllingColorSpace/\"> Read more in our docs! </Link>\r\n </>\r\n )\r\n }\r\n >\r\n {label}\r\n </InfoLabel>\r\n ) : (\r\n <Label htmlFor={id}>{label}</Label>\r\n )}\r\n <Input\r\n disabled={linearHex ? !isLinearMode : false}\r\n className={styles.input}\r\n value={linearHex ? value.toLinearSpace().toHexString() : value.toHexString()}\r\n id={id}\r\n onChange={handleChange}\r\n />\r\n </div>\r\n );\r\n};\r\n\r\ntype RgbKey = \"r\" | \"g\" | \"b\";\r\ntype InputRgbFieldProps = {\r\n color: Color3 | Color4;\r\n label: string;\r\n rgbKey: RgbKey;\r\n onChange: (color: Color3 | Color4) => void;\r\n};\r\n\r\nconst InputRgbField: FunctionComponent<InputRgbFieldProps> = (props) => {\r\n const { color, onChange, label, rgbKey } = props;\r\n const id = useId(`${label.toLowerCase()}-input`);\r\n const classes = useColorPickerStyles();\r\n\r\n const handleChange = useCallback(\r\n (_: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n const val = data.value ?? parseFloat(data.displayValue ?? \"\");\r\n\r\n if (val === null || Number.isNaN(val) || !NUMBER_REGEX.test(val.toString())) {\r\n return;\r\n }\r\n\r\n const newColor = color.clone();\r\n newColor[rgbKey] = val / 255.0; // Convert to 0-1 range\r\n onChange(newColor);\r\n },\r\n [color]\r\n );\r\n\r\n return (\r\n <div className={classes.colorFieldWrapper}>\r\n <Label htmlFor={id}>{label}</Label>\r\n <SpinButton className={classes.spinButton} min={0} max={255} value={color[rgbKey] * 255.0} step={1} id={id} onChange={handleChange} name={rgbKey} />\r\n </div>\r\n );\r\n};\r\n\r\ntype InputHsvFieldProps = {\r\n color: Color3 | Color4;\r\n label: string;\r\n hsvKey: HsvKey;\r\n onChange: (color: Color3 | Color4) => void;\r\n max: number;\r\n scale?: number;\r\n};\r\n\r\n/**\r\n * In the HSV (Hue, Saturation, Value) color model, Hue (H) ranges from 0 to 360 degrees, representing the color's position on the color wheel.\r\n * Saturation (S) ranges from 0 to 100%, indicating the intensity or purity of the color, with 0 being shades of gray and 100 being a fully saturated color.\r\n * Value (V) ranges from 0 to 100%, representing the brightness of the color, with 0 being black and 100 being the brightest.\r\n * @param props - The properties for the InputHsvField component.\r\n */\r\nexport const InputHsvField: FunctionComponent<InputHsvFieldProps> = (props) => {\r\n const { color, label, hsvKey, max, scale = 1 } = props;\r\n\r\n const id = useId(`${label.toLowerCase()}-input`);\r\n const classes = useColorPickerStyles();\r\n\r\n const handleChange = useCallback(\r\n (_: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n const val = data.value ?? parseFloat(data.displayValue ?? \"\");\r\n\r\n if (val === null || Number.isNaN(val) || !NUMBER_REGEX.test(val.toString())) {\r\n return;\r\n }\r\n\r\n // Convert current color to HSV, update the new hsv value, then call onChange prop\r\n const hsv = rgbaToHsv(color);\r\n hsv[hsvKey] = val / scale;\r\n let newColor: Color3 | Color4 = Color3.FromHSV(hsv.h, hsv.s, hsv.v);\r\n if (color instanceof Color4) {\r\n newColor = Color4.FromColor3(newColor, color.a ?? 1);\r\n }\r\n props.onChange(newColor);\r\n },\r\n [color]\r\n );\r\n\r\n return (\r\n <div className={classes.colorFieldWrapper}>\r\n <Label htmlFor={id}>{label}</Label>\r\n <SpinButton className={classes.spinButton} min={0} max={max} value={rgbaToHsv(color)[hsvKey] * scale} step={1} id={id} onChange={handleChange} name={hsvKey} />\r\n </div>\r\n );\r\n};\r\n\r\ntype InputAlphaProps = {\r\n color: Color3 | Color4;\r\n onChange: (color: Color4) => void;\r\n};\r\n\r\n/**\r\n * 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).\r\n * @param props\r\n * @returns\r\n */\r\nconst InputAlphaField: FunctionComponent<InputAlphaProps> = (props) => {\r\n const classes = useColorPickerStyles();\r\n const id = useId(\"alpha-input\");\r\n const { color } = props;\r\n\r\n const onChange = (_: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n const value = data.value ?? parseFloat(data.displayValue ?? \"\");\r\n\r\n if (Number.isNaN(value) || value < 0 || value > 1) {\r\n return;\r\n }\r\n\r\n if (color instanceof Color4) {\r\n const newColor = color.clone();\r\n newColor.a = value;\r\n return newColor;\r\n } else {\r\n return Color4.FromColor3(color, value);\r\n }\r\n };\r\n\r\n return (\r\n <div className={classes.colorFieldWrapper}>\r\n <div className={classes.row}>\r\n <Label htmlFor={id}>Alpha</Label>\r\n {color instanceof Color3 && (\r\n <InfoLabel\r\n htmlFor={id}\r\n info={\r\n <>\r\n Because this color picker is representing a Color3, we do not permit modifying alpha from the color picker. You can however modify the material's\r\n alpha property directly, either in code via material.alpha OR via inspector's transparency section.\r\n </>\r\n }\r\n ></InfoLabel>\r\n )}\r\n </div>\r\n <SpinButton\r\n disabled={color instanceof Color3}\r\n min={0}\r\n max={1}\r\n className={classes.spinButton}\r\n value={color instanceof Color3 ? 1 : color.a}\r\n step={0.01}\r\n onChange={onChange}\r\n id={id}\r\n />\r\n </div>\r\n );\r\n};\r\n\r\nconst NUMBER_REGEX = /^\\d+$/;\r\n\r\nfunction rgbaToHsv(color: { r: number; g: number; b: number; a?: number }): { h: number; s: number; v: number; a?: number } {\r\n const c = new Color3(color.r, color.g, color.b);\r\n const hsv = c.toHSV();\r\n return { h: hsv.r, s: hsv.g, v: hsv.b, a: color.a };\r\n}\r\n"]}
|
@@ -1,23 +1,23 @@
|
|
1
1
|
import type { FunctionComponent } from "react";
|
2
|
+
import type { BaseComponentProps } from "../hoc/propertyLine.js";
|
3
|
+
export type AcceptedDropdownValue = string | number;
|
2
4
|
export type DropdownOption = {
|
3
5
|
/**
|
4
6
|
* Defines the visible part of the option
|
5
7
|
*/
|
6
8
|
label: string;
|
7
9
|
/**
|
8
|
-
* Defines the value part of the option
|
10
|
+
* Defines the value part of the option
|
9
11
|
*/
|
10
|
-
value:
|
12
|
+
value: AcceptedDropdownValue;
|
11
13
|
};
|
12
|
-
type DropdownProps = {
|
13
|
-
options:
|
14
|
-
|
15
|
-
defaultValue?: DropdownOption;
|
14
|
+
export type DropdownProps = BaseComponentProps<AcceptedDropdownValue | undefined> & {
|
15
|
+
options: DropdownOption[];
|
16
|
+
includeUndefined?: boolean;
|
16
17
|
};
|
17
18
|
/**
|
18
|
-
* Renders a fluent UI dropdown
|
19
|
+
* Renders a fluent UI dropdown component for the options passed in, and an additional 'Not Defined' option if includeUndefined is set to true
|
19
20
|
* @param props
|
20
21
|
* @returns dropdown component
|
21
22
|
*/
|
22
23
|
export declare const Dropdown: FunctionComponent<DropdownProps>;
|
23
|
-
export {};
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
2
|
import { Dropdown as FluentDropdown, makeStyles, Option } from "@fluentui/react-components";
|
3
|
+
import { useEffect, useState } from "react";
|
3
4
|
const useDropdownStyles = makeStyles({
|
4
5
|
dropdownOption: {
|
5
6
|
textAlign: "right",
|
@@ -8,14 +9,24 @@ const useDropdownStyles = makeStyles({
|
|
8
9
|
optionsLine: {},
|
9
10
|
});
|
10
11
|
/**
|
11
|
-
* Renders a fluent UI dropdown
|
12
|
+
* Renders a fluent UI dropdown component for the options passed in, and an additional 'Not Defined' option if includeUndefined is set to true
|
12
13
|
* @param props
|
13
14
|
* @returns dropdown component
|
14
15
|
*/
|
15
16
|
export const Dropdown = (props) => {
|
16
17
|
const classes = useDropdownStyles();
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
const [options] = useState(props.includeUndefined ? [{ label: "<Not defined>", value: Number.NaN }, ...props.options] : props.options);
|
19
|
+
const [defaultVal, setDefaultVal] = useState(props.includeUndefined && props.value === undefined ? Number.NaN : props.value);
|
20
|
+
useEffect(() => {
|
21
|
+
setDefaultVal(props.includeUndefined && props.value === undefined ? Number.NaN : props.value);
|
22
|
+
}, [props.value]);
|
23
|
+
return (_jsx(FluentDropdown, { size: "small", className: classes.dropdownOption, onOptionSelect: (evt, data) => {
|
24
|
+
let value = typeof props.value === "number" ? Number(data.optionValue) : data.optionValue;
|
25
|
+
setDefaultVal(value);
|
26
|
+
if (props.includeUndefined && value === Number.NaN.toString()) {
|
27
|
+
value = undefined;
|
28
|
+
}
|
29
|
+
props.onChange(value);
|
30
|
+
}, value: options.find((o) => o.value === defaultVal)?.label, children: options.map((option) => (_jsx(Option, { className: classes.optionsLine, value: option.value?.toString(), disabled: false, children: option.label }, option.label))) }));
|
20
31
|
};
|
21
32
|
//# sourceMappingURL=dropdown.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"dropdown.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/dropdown.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;
|
1
|
+
{"version":3,"file":"dropdown.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/dropdown.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAI5C,MAAM,iBAAiB,GAAG,UAAU,CAAC;IACjC,cAAc,EAAE;QACZ,SAAS,EAAE,OAAO;QAClB,QAAQ,EAAE,MAAM;KACnB;IACD,WAAW,EAAE,EAAE;CAClB,CAAC,CAAC;AAoBH;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAqC,CAAC,KAAK,EAAE,EAAE;IAChE,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAmB,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzJ,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7H,SAAS,CAAC,GAAG,EAAE;QACX,aAAa,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAElB,OAAO,CACH,KAAC,cAAc,IACX,IAAI,EAAC,OAAO,EACZ,SAAS,EAAE,OAAO,CAAC,cAAc,EACjC,cAAc,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YAC1B,IAAI,KAAK,GAAG,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;YAC1F,aAAa,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,KAAK,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC5D,KAAK,GAAG,SAAS,CAAC;YACtB,CAAC;YACD,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC,EACD,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,EAAE,KAAK,YAExD,OAAO,CAAC,GAAG,CAAC,CAAC,MAAsB,EAAE,EAAE,CAAC,CACrC,KAAC,MAAM,IAAC,SAAS,EAAE,OAAO,CAAC,WAAW,EAAqB,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,YACtG,MAAM,CAAC,KAAK,IAD4B,MAAM,CAAC,KAAK,CAEhD,CACZ,CAAC,GACW,CACpB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { Dropdown as FluentDropdown, makeStyles, Option } from \"@fluentui/react-components\";\r\nimport { useEffect, useState } from \"react\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport type { BaseComponentProps } from \"../hoc/propertyLine\";\r\n\r\nconst useDropdownStyles = makeStyles({\r\n dropdownOption: {\r\n textAlign: \"right\",\r\n minWidth: \"40px\",\r\n },\r\n optionsLine: {},\r\n});\r\n\r\nexport type AcceptedDropdownValue = string | number;\r\nexport type DropdownOption = {\r\n /**\r\n * Defines the visible part of the option\r\n */\r\n label: string;\r\n /**\r\n * Defines the value part of the option\r\n */\r\n value: AcceptedDropdownValue;\r\n};\r\n\r\nexport type DropdownProps = BaseComponentProps<AcceptedDropdownValue | undefined> & {\r\n options: DropdownOption[];\r\n\r\n includeUndefined?: boolean; // If true, adds an option with label 'Not Defined' and value undefined\r\n};\r\n\r\n/**\r\n * Renders a fluent UI dropdown component for the options passed in, and an additional 'Not Defined' option if includeUndefined is set to true\r\n * @param props\r\n * @returns dropdown component\r\n */\r\nexport const Dropdown: FunctionComponent<DropdownProps> = (props) => {\r\n const classes = useDropdownStyles();\r\n const [options] = useState<DropdownOption[]>(props.includeUndefined ? [{ label: \"<Not defined>\", value: Number.NaN }, ...props.options] : props.options);\r\n const [defaultVal, setDefaultVal] = useState(props.includeUndefined && props.value === undefined ? Number.NaN : props.value);\r\n useEffect(() => {\r\n setDefaultVal(props.includeUndefined && props.value === undefined ? Number.NaN : props.value);\r\n }, [props.value]);\r\n\r\n return (\r\n <FluentDropdown\r\n size=\"small\"\r\n className={classes.dropdownOption}\r\n onOptionSelect={(evt, data) => {\r\n let value = typeof props.value === \"number\" ? Number(data.optionValue) : data.optionValue;\r\n setDefaultVal(value);\r\n if (props.includeUndefined && value === Number.NaN.toString()) {\r\n value = undefined;\r\n }\r\n props.onChange(value);\r\n }}\r\n value={options.find((o) => o.value === defaultVal)?.label}\r\n >\r\n {options.map((option: DropdownOption) => (\r\n <Option className={classes.optionsLine} key={option.label} value={option.value?.toString()} disabled={false}>\r\n {option.label}\r\n </Option>\r\n ))}\r\n </FluentDropdown>\r\n );\r\n};\r\n"]}
|