@onerjs/shared-ui-components 8.28.0 → 8.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,8 @@
1
- import type { PropertyLineProps } from "./propertyLine.js";
2
1
  import type { FunctionComponent } from "react";
3
- import type { InputHexProps } from "../../primitives/colorPicker.js";
4
- import type { Color3, Color4 } from "@onerjs/core/Maths/math.color.js";
2
+ import type { NumberInputPropertyLineProps } from "./inputPropertyLine.js";
5
3
  /**
6
- * Wraps a hex input in a property line
7
- * @param props - PropertyLineProps and InputHexProps
8
- * @returns property-line wrapped input hex component
4
+ * Takes a number representing a Hex value and converts it to a hex string then wraps the TextInput in a PropertyLine
5
+ * @param props - PropertyLineProps
6
+ * @returns property-line wrapped textbox that converts to/from hex number representation
9
7
  */
10
- export declare const HexPropertyLine: FunctionComponent<InputHexProps & PropertyLineProps<Color3 | Color4>>;
8
+ export declare const HexPropertyLine: FunctionComponent<NumberInputPropertyLineProps>;
@@ -1,13 +1,58 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { PropertyLine } from "./propertyLine.js";
3
- import { InputHexField } from "../../primitives/colorPicker.js";
3
+ import { useEffect, useState } from "react";
4
+ import { TextInput } from "../../primitives/textInput.js";
5
+ // The below conversion functions are taken from old HexLineComponent and can likely be simplified
6
+ const ConvertToHexString = (valueString) => {
7
+ while (valueString.length < 10) {
8
+ valueString += "0";
9
+ }
10
+ return valueString;
11
+ };
12
+ const MaskValidatorFn = (valueString) => {
13
+ if (valueString.substring(0, 2) != "0x") {
14
+ if (valueString.substring(0, 1) != "0") {
15
+ valueString = "0x" + valueString;
16
+ }
17
+ else {
18
+ valueString = "0x" + valueString.substr(1);
19
+ }
20
+ }
21
+ const valueSubstr = valueString.substr(2);
22
+ if (valueSubstr != "" && /^[0-9A-Fa-f]+$/g.test(valueSubstr) == false) {
23
+ return false;
24
+ }
25
+ if (valueString.length > 10) {
26
+ return false;
27
+ }
28
+ return true;
29
+ };
30
+ const GetHexValFromNumber = (val) => {
31
+ let valueAsHex = val.toString(16);
32
+ let hex0String = "";
33
+ for (let i = 0; i < 8 - valueAsHex.length; i++) {
34
+ // padding the '0's
35
+ hex0String += "0";
36
+ }
37
+ valueAsHex = "0x" + hex0String + valueAsHex.toUpperCase();
38
+ return valueAsHex;
39
+ };
4
40
  /**
5
- * Wraps a hex input in a property line
6
- * @param props - PropertyLineProps and InputHexProps
7
- * @returns property-line wrapped input hex component
41
+ * Takes a number representing a Hex value and converts it to a hex string then wraps the TextInput in a PropertyLine
42
+ * @param props - PropertyLineProps
43
+ * @returns property-line wrapped textbox that converts to/from hex number representation
8
44
  */
9
45
  export const HexPropertyLine = (props) => {
10
46
  HexPropertyLine.displayName = "HexPropertyLine";
11
- return (_jsx(PropertyLine, { ...props, children: _jsx(InputHexField, { ...props }) }));
47
+ const [hexVal, setHexVal] = useState(GetHexValFromNumber(props.value));
48
+ const onStrValChange = (val) => {
49
+ setHexVal(val);
50
+ const valueStringAsHex = ConvertToHexString(val);
51
+ props.onChange(parseInt(valueStringAsHex));
52
+ };
53
+ useEffect(() => {
54
+ setHexVal(GetHexValFromNumber(props.value));
55
+ }, [props.value]);
56
+ return (_jsx(PropertyLine, { ...props, children: _jsx(TextInput, { ...props, validator: MaskValidatorFn, value: hexVal, onChange: onStrValChange }) }));
12
57
  };
13
58
  //# sourceMappingURL=hexPropertyLine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hexPropertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/hexPropertyLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAI7D;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAA0E,CAAC,KAAK,EAAE,EAAE;IAC5G,eAAe,CAAC,WAAW,GAAG,iBAAiB,CAAC;IAChD,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,aAAa,OAAK,KAAK,GAAI,GACjB,CAClB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { PropertyLine } from \"./propertyLine\";\r\nimport type { PropertyLineProps } from \"./propertyLine\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport { InputHexField } from \"../../primitives/colorPicker\";\r\nimport type { InputHexProps } from \"../../primitives/colorPicker\";\r\nimport type { Color3, Color4 } from \"core/Maths/math.color\";\r\n\r\n/**\r\n * Wraps a hex input in a property line\r\n * @param props - PropertyLineProps and InputHexProps\r\n * @returns property-line wrapped input hex component\r\n */\r\nexport const HexPropertyLine: FunctionComponent<InputHexProps & PropertyLineProps<Color3 | Color4>> = (props) => {\r\n HexPropertyLine.displayName = \"HexPropertyLine\";\r\n return (\r\n <PropertyLine {...props}>\r\n <InputHexField {...props} />\r\n </PropertyLine>\r\n );\r\n};\r\n"]}
1
+ {"version":3,"file":"hexPropertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/hexPropertyLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,kGAAkG;AAClG,MAAM,kBAAkB,GAAG,CAAC,WAAmB,EAAU,EAAE;IACvD,OAAO,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC7B,WAAW,IAAI,GAAG,CAAC;IACvB,CAAC;IACD,OAAO,WAAW,CAAC;AACvB,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,WAAmB,EAAE,EAAE;IAC5C,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACtC,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;YACrC,WAAW,GAAG,IAAI,GAAG,WAAW,CAAC;QACrC,CAAC;aAAM,CAAC;YACJ,WAAW,GAAG,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1C,IAAI,WAAW,IAAI,EAAE,IAAI,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,EAAE,CAAC;QACpE,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAU,EAAE;IAChD,IAAI,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,mBAAmB;QACnB,UAAU,IAAI,GAAG,CAAC;IACtB,CAAC;IACD,UAAU,GAAG,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAC1D,OAAO,UAAU,CAAC;AACtB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAoD,CAAC,KAAK,EAAE,EAAE;IACtF,eAAe,CAAC,WAAW,GAAG,iBAAiB,CAAC;IAChD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAEvE,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,EAAE;QACnC,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjD,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACX,SAAS,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAElB,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,SAAS,OAAK,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAI,GAClF,CAClB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { PropertyLine } from \"./propertyLine\";\r\nimport { useEffect, useState } from \"react\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport type { NumberInputPropertyLineProps } from \"./inputPropertyLine\";\r\nimport { TextInput } from \"../../primitives/textInput\";\r\n\r\n// The below conversion functions are taken from old HexLineComponent and can likely be simplified\r\nconst ConvertToHexString = (valueString: string): string => {\r\n while (valueString.length < 10) {\r\n valueString += \"0\";\r\n }\r\n return valueString;\r\n};\r\n\r\nconst MaskValidatorFn = (valueString: string) => {\r\n if (valueString.substring(0, 2) != \"0x\") {\r\n if (valueString.substring(0, 1) != \"0\") {\r\n valueString = \"0x\" + valueString;\r\n } else {\r\n valueString = \"0x\" + valueString.substr(1);\r\n }\r\n }\r\n\r\n const valueSubstr = valueString.substr(2);\r\n if (valueSubstr != \"\" && /^[0-9A-Fa-f]+$/g.test(valueSubstr) == false) {\r\n return false;\r\n }\r\n\r\n if (valueString.length > 10) {\r\n return false;\r\n }\r\n\r\n return true;\r\n};\r\n\r\nconst GetHexValFromNumber = (val: number): string => {\r\n let valueAsHex = val.toString(16);\r\n let hex0String = \"\";\r\n for (let i = 0; i < 8 - valueAsHex.length; i++) {\r\n // padding the '0's\r\n hex0String += \"0\";\r\n }\r\n valueAsHex = \"0x\" + hex0String + valueAsHex.toUpperCase();\r\n return valueAsHex;\r\n};\r\n\r\n/**\r\n * Takes a number representing a Hex value and converts it to a hex string then wraps the TextInput in a PropertyLine\r\n * @param props - PropertyLineProps\r\n * @returns property-line wrapped textbox that converts to/from hex number representation\r\n */\r\nexport const HexPropertyLine: FunctionComponent<NumberInputPropertyLineProps> = (props) => {\r\n HexPropertyLine.displayName = \"HexPropertyLine\";\r\n const [hexVal, setHexVal] = useState(GetHexValFromNumber(props.value));\r\n\r\n const onStrValChange = (val: string) => {\r\n setHexVal(val);\r\n const valueStringAsHex = ConvertToHexString(val);\r\n props.onChange(parseInt(valueStringAsHex));\r\n };\r\n\r\n useEffect(() => {\r\n setHexVal(GetHexValFromNumber(props.value));\r\n }, [props.value]);\r\n\r\n return (\r\n <PropertyLine {...props}>\r\n <TextInput {...props} validator={MaskValidatorFn} value={hexVal} onChange={onStrValChange} />\r\n </PropertyLine>\r\n );\r\n};\r\n"]}
@@ -8,12 +8,11 @@ import type { SpinButtonProps } from "../../primitives/spinButton.js";
8
8
  * @returns property-line wrapped input component
9
9
  */
10
10
  export declare const TextInputPropertyLine: FunctionComponent<TextInputProps & PropertyLineProps<string>>;
11
+ export type NumberInputPropertyLineProps = SpinButtonProps & PropertyLineProps<number>;
11
12
  /**
12
13
  * Wraps a number input in a property line
13
14
  * 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)
14
15
  * @param props - PropertyLineProps and InputProps
15
16
  * @returns property-line wrapped input component
16
17
  */
17
- export declare const NumberInputPropertyLine: FunctionComponent<SpinButtonProps & PropertyLineProps<number> & {
18
- forceInt?: boolean;
19
- }>;
18
+ export declare const NumberInputPropertyLine: FunctionComponent<NumberInputPropertyLineProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"inputPropertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/inputPropertyLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI9C,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAkE,CAAC,KAAK,EAAE,EAAE;IAC1G,qBAAqB,CAAC,WAAW,GAAG,uBAAuB,CAAC;IAC5D,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,SAAS,OAAK,KAAK,GAAI,GACb,CAClB,CAAC;AACN,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAA4F,CAAC,KAAK,EAAE,EAAE;IACtI,uBAAuB,CAAC,WAAW,GAAG,yBAAyB,CAAC;IAChE,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,UAAU,OAAK,KAAK,GAAI,GACd,CAClB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { PropertyLine } from \"./propertyLine\";\r\nimport type { PropertyLineProps } from \"./propertyLine\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport type { TextInputProps } from \"../../primitives/textInput\";\r\nimport { TextInput } from \"../../primitives/textInput\";\r\nimport type { SpinButtonProps } from \"../../primitives/spinButton\";\r\nimport { SpinButton } from \"../../primitives/spinButton\";\r\n/**\r\n * Wraps a text input in a property line\r\n * @param props - PropertyLineProps and InputProps\r\n * @returns property-line wrapped input component\r\n */\r\nexport const TextInputPropertyLine: FunctionComponent<TextInputProps & PropertyLineProps<string>> = (props) => {\r\n TextInputPropertyLine.displayName = \"TextInputPropertyLine\";\r\n return (\r\n <PropertyLine {...props}>\r\n <TextInput {...props} />\r\n </PropertyLine>\r\n );\r\n};\r\n\r\n/**\r\n * Wraps a number input in a property line\r\n * 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)\r\n * @param props - PropertyLineProps and InputProps\r\n * @returns property-line wrapped input component\r\n */\r\nexport const NumberInputPropertyLine: FunctionComponent<SpinButtonProps & PropertyLineProps<number> & { forceInt?: boolean }> = (props) => {\r\n NumberInputPropertyLine.displayName = \"NumberInputPropertyLine\";\r\n return (\r\n <PropertyLine {...props}>\r\n <SpinButton {...props} />\r\n </PropertyLine>\r\n );\r\n};\r\n"]}
1
+ {"version":3,"file":"inputPropertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/inputPropertyLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI9C,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAkE,CAAC,KAAK,EAAE,EAAE;IAC1G,qBAAqB,CAAC,WAAW,GAAG,uBAAuB,CAAC;IAC5D,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,SAAS,OAAK,KAAK,GAAI,GACb,CAClB,CAAC;AACN,CAAC,CAAC;AAGF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAoD,CAAC,KAAK,EAAE,EAAE;IAC9F,uBAAuB,CAAC,WAAW,GAAG,yBAAyB,CAAC;IAChE,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,UAAU,OAAK,KAAK,GAAI,GACd,CAClB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { PropertyLine } from \"./propertyLine\";\r\nimport type { PropertyLineProps } from \"./propertyLine\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport type { TextInputProps } from \"../../primitives/textInput\";\r\nimport { TextInput } from \"../../primitives/textInput\";\r\nimport type { SpinButtonProps } from \"../../primitives/spinButton\";\r\nimport { SpinButton } from \"../../primitives/spinButton\";\r\n/**\r\n * Wraps a text input in a property line\r\n * @param props - PropertyLineProps and InputProps\r\n * @returns property-line wrapped input component\r\n */\r\nexport const TextInputPropertyLine: FunctionComponent<TextInputProps & PropertyLineProps<string>> = (props) => {\r\n TextInputPropertyLine.displayName = \"TextInputPropertyLine\";\r\n return (\r\n <PropertyLine {...props}>\r\n <TextInput {...props} />\r\n </PropertyLine>\r\n );\r\n};\r\n\r\nexport type NumberInputPropertyLineProps = SpinButtonProps & PropertyLineProps<number>;\r\n/**\r\n * Wraps a number input in a property line\r\n * 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)\r\n * @param props - PropertyLineProps and InputProps\r\n * @returns property-line wrapped input component\r\n */\r\nexport const NumberInputPropertyLine: FunctionComponent<NumberInputPropertyLineProps> = (props) => {\r\n NumberInputPropertyLine.displayName = \"NumberInputPropertyLine\";\r\n return (\r\n <PropertyLine {...props}>\r\n <SpinButton {...props} />\r\n </PropertyLine>\r\n );\r\n};\r\n"]}
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useEffect, useState } from "react";
3
3
  import { Body1 } from "@fluentui/react-components";
4
4
  import { PropertyLine } from "./propertyLine.js";
5
5
  import { SyncedSliderPropertyLine } from "./syncedSliderPropertyLine.js";
6
6
  import { Quaternion, Vector2, Vector4 } from "@onerjs/core/Maths/math.vector.js";
7
7
  import { Tools } from "@onerjs/core/Misc/tools.js";
8
- import { CalculatePrecision } from "../../primitives/spinButton.js";
8
+ import { CalculatePrecision } from "../../primitives/utils.js";
9
9
  const HasZ = (vector) => !(vector instanceof Vector2);
10
10
  const HasW = (vector) => vector instanceof Vector4 || vector instanceof Quaternion;
11
11
  /**
@@ -17,7 +17,7 @@ const HasW = (vector) => vector instanceof Vector4 || vector instanceof Quaterni
17
17
  const TensorPropertyLine = (props) => {
18
18
  TensorPropertyLine.displayName = "TensorPropertyLine";
19
19
  const converted = (val) => (props.valueConverter ? props.valueConverter.from(val) : val);
20
- const formatted = (val) => converted(val).toFixed(props.step !== undefined ? CalculatePrecision(props.step) : 2);
20
+ const formatted = (val) => converted(val).toFixed(props.step !== undefined ? Math.max(0, CalculatePrecision(props.step)) : 2);
21
21
  const [vector, setVector] = useState(props.value);
22
22
  const { min, max } = props;
23
23
  const onChange = (val, key) => {
@@ -27,6 +27,9 @@ const TensorPropertyLine = (props) => {
27
27
  setVector(newVector);
28
28
  props.onChange(newVector);
29
29
  };
30
+ useEffect(() => {
31
+ setVector(props.value);
32
+ }, [props.value, props.expandedContent]);
30
33
  return (_jsx(PropertyLine, { ...props, onCopy: () => `new ${props.value.constructor.name}(${vector.x},${vector.y} ${HasZ(vector) ? `,${vector.z}` : ""}${HasW(vector) ? `,${vector.w}` : ""})`, expandedContent: _jsxs(_Fragment, { children: [_jsx(SyncedSliderPropertyLine, { label: "X", value: converted(vector.x), min: min, max: max, onChange: (val) => onChange(val, "x"), unit: props.unit, step: props.step }), _jsx(SyncedSliderPropertyLine, { label: "Y", value: converted(vector.y), min: min, max: max, onChange: (val) => onChange(val, "y"), unit: props.unit, step: props.step }), HasZ(vector) && (_jsx(SyncedSliderPropertyLine, { label: "Z", value: converted(vector.z), min: min, max: max, onChange: (val) => onChange(val, "z"), unit: props.unit, step: props.step })), HasW(vector) && (_jsx(SyncedSliderPropertyLine, { label: "W", value: converted(vector.w), min: min, max: max, onChange: (val) => onChange(val, "w"), unit: props.unit, step: props.step }))] }), children: _jsx(Body1, { children: `[${formatted(props.value.x)}, ${formatted(props.value.y)}${HasZ(props.value) ? `, ${formatted(props.value.z)}` : ""}${HasW(props.value) ? `, ${formatted(props.value.w)}` : ""}]` }) }));
31
34
  };
32
35
  const ToDegreesConverter = { from: Tools.ToDegrees, to: Tools.ToRadians };
@@ -1 +1 @@
1
- {"version":3,"file":"vectorPropertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/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 { PrimitiveProps } from \"../../primitives/primitive\";\r\nimport type { PropertyLineProps } from \"./propertyLine\";\r\n\r\nimport { SyncedSliderPropertyLine } from \"./syncedSliderPropertyLine\";\r\nimport type { Vector3 } from \"core/Maths/math.vector\";\r\nimport { Quaternion, Vector2, Vector4 } from \"core/Maths/math.vector\";\r\nimport { Tools } from \"core/Misc/tools\";\r\nimport { CalculatePrecision } from \"../../primitives/spinButton\";\r\n\r\nexport type TensorPropertyLineProps<V extends Vector2 | Vector3 | Vector4 | Quaternion> = PropertyLineProps<V> &\r\n PrimitiveProps<V> & {\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 * Will be displayed in the input UI to indicate the unit of measurement\r\n */\r\n unit?: string;\r\n\r\n /**\r\n * Internal spinbutton's step\r\n */\r\n step?: 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\nconst HasZ = (vector: Vector2 | Vector3 | Vector4 | Quaternion): vector is Vector3 => !(vector instanceof Vector2);\r\nconst HasW = (vector: Vector2 | Vector3 | Vector4 | Quaternion): vector is Vector4 => vector instanceof Vector4 || vector instanceof Quaternion;\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 TensorPropertyLine: FunctionComponent<TensorPropertyLineProps<Vector2 | Vector3 | Vector4 | Quaternion>> = (props) => {\r\n TensorPropertyLine.displayName = \"TensorPropertyLine\";\r\n const converted = (val: number) => (props.valueConverter ? props.valueConverter.from(val) : val);\r\n const formatted = (val: number) => converted(val).toFixed(props.step !== undefined ? CalculatePrecision(props.step) : 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 onCopy={() => `new ${props.value.constructor.name}(${vector.x},${vector.y} ${HasZ(vector) ? `,${vector.z}` : \"\"}${HasW(vector) ? `,${vector.w}` : \"\"})`}\r\n expandedContent={\r\n <>\r\n <SyncedSliderPropertyLine\r\n label=\"X\"\r\n value={converted(vector.x)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"x\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n <SyncedSliderPropertyLine\r\n label=\"Y\"\r\n value={converted(vector.y)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"y\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n {HasZ(vector) && (\r\n <SyncedSliderPropertyLine\r\n label=\"Z\"\r\n value={converted(vector.z)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"z\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n )}\r\n {HasW(vector) && (\r\n <SyncedSliderPropertyLine\r\n label=\"W\"\r\n value={converted(vector.w)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"w\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n )}\r\n </>\r\n }\r\n >\r\n <Body1>{`[${formatted(props.value.x)}, ${formatted(props.value.y)}${HasZ(props.value) ? `, ${formatted(props.value.z)}` : \"\"}${HasW(props.value) ? `, ${formatted(props.value.w)}` : \"\"}]`}</Body1>\r\n </PropertyLine>\r\n );\r\n};\r\n\r\ntype RotationVectorPropertyLineProps = TensorPropertyLineProps<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 RotationVectorPropertyLine.displayName = \"RotationVectorPropertyLine\";\r\n const min = props.useDegrees ? 0 : undefined;\r\n const max = props.useDegrees ? 360 : undefined;\r\n return (\r\n <Vector3PropertyLine\r\n {...props}\r\n unit={props.useDegrees ? \"deg\" : \"rad\"}\r\n valueConverter={props.useDegrees ? ToDegreesConverter : undefined}\r\n min={min}\r\n max={max}\r\n step={0.001}\r\n />\r\n );\r\n};\r\n\r\ntype QuaternionPropertyLineProps = TensorPropertyLineProps<Quaternion> & {\r\n /**\r\n * Display angles as degrees instead of radians\r\n */\r\n useDegrees?: boolean;\r\n};\r\nconst QuaternionPropertyLineInternal = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Quaternion>>;\r\nexport const QuaternionPropertyLine: FunctionComponent<QuaternionPropertyLineProps> = (props) => {\r\n QuaternionPropertyLine.displayName = \"QuaternionPropertyLine\";\r\n const min = props.useDegrees ? 0 : undefined;\r\n const max = props.useDegrees ? 360 : undefined;\r\n const [quat, setQuat] = useState(props.value);\r\n\r\n // Extract only the properties that exist on QuaternionPropertyLineProps\r\n const { useDegrees, ...restProps } = props;\r\n\r\n const onQuatChange = (val: Quaternion) => {\r\n setQuat(val);\r\n props.onChange(val);\r\n };\r\n\r\n const onEulerChange = (val: Vector3) => {\r\n const quat = Quaternion.FromEulerAngles(val.x, val.y, val.z);\r\n setQuat(quat);\r\n props.onChange(quat);\r\n };\r\n\r\n return useDegrees ? (\r\n <Vector3PropertyLine\r\n {...restProps}\r\n nullable={false}\r\n ignoreNullable={false}\r\n value={quat.toEulerAngles()}\r\n valueConverter={ToDegreesConverter}\r\n min={min}\r\n max={max}\r\n onChange={onEulerChange}\r\n unit=\"deg\"\r\n />\r\n ) : (\r\n <QuaternionPropertyLineInternal {...props} unit={\"rad\"} nullable={false} value={quat} min={min} max={max} onChange={onQuatChange} />\r\n );\r\n};\r\nexport const Vector2PropertyLine = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Vector2>>;\r\nexport const Vector3PropertyLine = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Vector3>>;\r\nexport const Vector4PropertyLine = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Vector4>>;\r\n"]}
1
+ {"version":3,"file":"vectorPropertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/vectorPropertyLine.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, 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 { PrimitiveProps } from \"../../primitives/primitive\";\r\nimport type { PropertyLineProps } from \"./propertyLine\";\r\n\r\nimport { SyncedSliderPropertyLine } from \"./syncedSliderPropertyLine\";\r\nimport type { Vector3 } from \"core/Maths/math.vector\";\r\nimport { Quaternion, Vector2, Vector4 } from \"core/Maths/math.vector\";\r\nimport { Tools } from \"core/Misc/tools\";\r\nimport { CalculatePrecision } from \"../../primitives/utils\";\r\n\r\nexport type TensorPropertyLineProps<V extends Vector2 | Vector3 | Vector4 | Quaternion> = PropertyLineProps<V> &\r\n PrimitiveProps<V> & {\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 * Will be displayed in the input UI to indicate the unit of measurement\r\n */\r\n unit?: string;\r\n\r\n /**\r\n * Internal spinbutton's step\r\n */\r\n step?: 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\nconst HasZ = (vector: Vector2 | Vector3 | Vector4 | Quaternion): vector is Vector3 => !(vector instanceof Vector2);\r\nconst HasW = (vector: Vector2 | Vector3 | Vector4 | Quaternion): vector is Vector4 => vector instanceof Vector4 || vector instanceof Quaternion;\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 TensorPropertyLine: FunctionComponent<TensorPropertyLineProps<Vector2 | Vector3 | Vector4 | Quaternion>> = (props) => {\r\n TensorPropertyLine.displayName = \"TensorPropertyLine\";\r\n const converted = (val: number) => (props.valueConverter ? props.valueConverter.from(val) : val);\r\n const formatted = (val: number) => converted(val).toFixed(props.step !== undefined ? Math.max(0, CalculatePrecision(props.step)) : 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 useEffect(() => {\r\n setVector(props.value);\r\n }, [props.value, props.expandedContent]);\r\n\r\n return (\r\n <PropertyLine\r\n {...props}\r\n onCopy={() => `new ${props.value.constructor.name}(${vector.x},${vector.y} ${HasZ(vector) ? `,${vector.z}` : \"\"}${HasW(vector) ? `,${vector.w}` : \"\"})`}\r\n expandedContent={\r\n <>\r\n <SyncedSliderPropertyLine\r\n label=\"X\"\r\n value={converted(vector.x)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"x\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n <SyncedSliderPropertyLine\r\n label=\"Y\"\r\n value={converted(vector.y)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"y\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n {HasZ(vector) && (\r\n <SyncedSliderPropertyLine\r\n label=\"Z\"\r\n value={converted(vector.z)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"z\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n )}\r\n {HasW(vector) && (\r\n <SyncedSliderPropertyLine\r\n label=\"W\"\r\n value={converted(vector.w)}\r\n min={min}\r\n max={max}\r\n onChange={(val) => onChange(val, \"w\")}\r\n unit={props.unit}\r\n step={props.step}\r\n />\r\n )}\r\n </>\r\n }\r\n >\r\n <Body1>{`[${formatted(props.value.x)}, ${formatted(props.value.y)}${HasZ(props.value) ? `, ${formatted(props.value.z)}` : \"\"}${HasW(props.value) ? `, ${formatted(props.value.w)}` : \"\"}]`}</Body1>\r\n </PropertyLine>\r\n );\r\n};\r\n\r\ntype RotationVectorPropertyLineProps = TensorPropertyLineProps<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 RotationVectorPropertyLine.displayName = \"RotationVectorPropertyLine\";\r\n const min = props.useDegrees ? 0 : undefined;\r\n const max = props.useDegrees ? 360 : undefined;\r\n return (\r\n <Vector3PropertyLine\r\n {...props}\r\n unit={props.useDegrees ? \"deg\" : \"rad\"}\r\n valueConverter={props.useDegrees ? ToDegreesConverter : undefined}\r\n min={min}\r\n max={max}\r\n step={0.001}\r\n />\r\n );\r\n};\r\n\r\ntype QuaternionPropertyLineProps = TensorPropertyLineProps<Quaternion> & {\r\n /**\r\n * Display angles as degrees instead of radians\r\n */\r\n useDegrees?: boolean;\r\n};\r\nconst QuaternionPropertyLineInternal = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Quaternion>>;\r\nexport const QuaternionPropertyLine: FunctionComponent<QuaternionPropertyLineProps> = (props) => {\r\n QuaternionPropertyLine.displayName = \"QuaternionPropertyLine\";\r\n const min = props.useDegrees ? 0 : undefined;\r\n const max = props.useDegrees ? 360 : undefined;\r\n const [quat, setQuat] = useState(props.value);\r\n\r\n // Extract only the properties that exist on QuaternionPropertyLineProps\r\n const { useDegrees, ...restProps } = props;\r\n\r\n const onQuatChange = (val: Quaternion) => {\r\n setQuat(val);\r\n props.onChange(val);\r\n };\r\n\r\n const onEulerChange = (val: Vector3) => {\r\n const quat = Quaternion.FromEulerAngles(val.x, val.y, val.z);\r\n setQuat(quat);\r\n props.onChange(quat);\r\n };\r\n\r\n return useDegrees ? (\r\n <Vector3PropertyLine\r\n {...restProps}\r\n nullable={false}\r\n ignoreNullable={false}\r\n value={quat.toEulerAngles()}\r\n valueConverter={ToDegreesConverter}\r\n min={min}\r\n max={max}\r\n onChange={onEulerChange}\r\n unit=\"deg\"\r\n />\r\n ) : (\r\n <QuaternionPropertyLineInternal {...props} unit={\"rad\"} nullable={false} value={quat} min={min} max={max} onChange={onQuatChange} />\r\n );\r\n};\r\nexport const Vector2PropertyLine = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Vector2>>;\r\nexport const Vector3PropertyLine = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Vector3>>;\r\nexport const Vector4PropertyLine = TensorPropertyLine as FunctionComponent<TensorPropertyLineProps<Vector4>>;\r\n"]}
@@ -7,6 +7,7 @@ import { Color3, Color4 } from "@onerjs/core/Maths/math.color.js";
7
7
  import { SpinButton } from "./spinButton.js";
8
8
  import { TextInput } from "./textInput.js";
9
9
  import { NumberDropdown } from "./dropdown.js";
10
+ import { ColorHexValidatorFn } from "./utils.js";
10
11
  const useColorPickerStyles = makeStyles({
11
12
  container: {
12
13
  width: "350px",
@@ -93,7 +94,6 @@ export const ColorPickerPopup = (props) => {
93
94
  { label: "Float", value: 1 },
94
95
  ], 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 }) })] }) })] }));
95
96
  };
96
- const HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8})$/);
97
97
  /**
98
98
  * Component which displays the passed in color's HEX value, either in linearSpace (if linearHex is true) or in gamma space
99
99
  * When the hex color is changed by user, component calculates the new Color3/4 value and calls onChange
@@ -105,7 +105,7 @@ const HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8})$/);
105
105
  export const InputHexField = (props) => {
106
106
  const classes = useColorPickerStyles();
107
107
  const { title, value, onChange, linearHex, isLinearMode } = props;
108
- 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
108
+ return (_jsx(TextInput, { disabled: linearHex ? !isLinearMode : false, className: classes.inputField, value: linearHex ? value.toLinearSpace().toHexString() : value.toHexString(), validator: ColorHexValidatorFn, onChange: (val) => (linearHex ? onChange(Color3.FromHexString(val).toGammaSpace()) : onChange(Color3.FromHexString(val))), infoLabel: title
109
109
  ? {
110
110
  label: title,
111
111
  // If not representing a linearHex, no info is needed.
@@ -1 +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 } from \"react\";\r\nimport {\r\n ColorPicker as FluentColorPicker,\r\n ColorSlider,\r\n ColorArea,\r\n AlphaSlider,\r\n Link,\r\n makeStyles,\r\n Popover,\r\n PopoverSurface,\r\n PopoverTrigger,\r\n tokens,\r\n Body1Strong,\r\n ColorSwatch,\r\n Body1,\r\n} from \"@fluentui/react-components\";\r\nimport type { ColorPickerProps as FluentColorPickerProps } from \"@fluentui/react-components\";\r\nimport { Color3, Color4 } from \"core/Maths/math.color\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { SpinButton } from \"./spinButton\";\r\nimport { TextInput } from \"./textInput\";\r\nimport { NumberDropdown } from \"./dropdown\";\r\n\r\nconst useColorPickerStyles = makeStyles({\r\n container: {\r\n width: \"350px\",\r\n display: \"flex\", // becomes a flexbox\r\n flexDirection: \"column\", // with children in a column\r\n alignItems: \"center\", // centers children horizontally\r\n justifyContent: \"center\", // centers children vertically (if height is set)\r\n gap: tokens.spacingVerticalM,\r\n overflow: \"visible\",\r\n },\r\n row: {\r\n flex: 1, // is a row in the container's flex column\r\n display: \"flex\", // becomes its own flexbox\r\n flexDirection: \"row\", // with children in a row\r\n gap: tokens.spacingHorizontalXL,\r\n alignItems: \"center\", // align items vertically\r\n width: \"100%\",\r\n },\r\n colorPicker: {\r\n flex: 1,\r\n width: \"350px\",\r\n height: \"350px\",\r\n },\r\n previewColor: {\r\n width: \"60px\",\r\n height: \"60px\",\r\n borderRadius: tokens.borderRadiusMedium, // 4px?\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 inputRow: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n flex: 1, // grow and fill available space\r\n justifyContent: \"center\",\r\n gap: \"10px\",\r\n width: \"100%\",\r\n },\r\n inputField: {\r\n flex: 1, // grow and fill available space\r\n width: \"auto\",\r\n minWidth: 0,\r\n gap: tokens.spacingVerticalSNudge, // 6px\r\n },\r\n});\r\n\r\nexport type ColorPickerProps<C extends Color3 | Color4> = {\r\n isLinearMode?: boolean;\r\n} & PrimitiveProps<C>;\r\n\r\nexport const ColorPickerPopup: FunctionComponent<ColorPickerProps<Color3 | Color4>> = (props) => {\r\n ColorPickerPopup.displayName = \"ColorPickerPopup\";\r\n const classes = useColorPickerStyles();\r\n const [color, setColor] = useState(props.value);\r\n const [popoverOpen, setPopoverOpen] = useState(false);\r\n const [isLinear, setIsLinear] = useState(props.isLinearMode ?? false);\r\n const [isFloat, setFloat] = useState(false);\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 handleColorPickerChange: 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 handleChange(color);\r\n };\r\n\r\n const handleChange = (newColor: Color3 | Color4) => {\r\n setColor(newColor);\r\n props.onChange(newColor); // Ensures the parent is notified when color changes from within colorPicker\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 <ColorSwatch borderColor={tokens.colorNeutralShadowKeyDarker} size=\"small\" shape=\"rounded\" color={color.toHexString()} value={color.toHexString().slice(1)} />\r\n </PopoverTrigger>\r\n\r\n <PopoverSurface>\r\n <div className={classes.container}>\r\n <FluentColorPicker className={classes.colorPicker} color={rgbaToHsv(color)} onColorChange={handleColorPickerChange}>\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 </FluentColorPicker>\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 <NumberDropdown\r\n className={classes.inputField}\r\n infoLabel={{\r\n label: \"Color Space\",\r\n info: <Body1>Today this is not mutable as the color space is determined by the entity. Soon we will allow swapping</Body1>,\r\n }}\r\n options={[\r\n { label: \"Gamma\", value: 0 },\r\n { label: \"Linear\", value: 1 },\r\n ]}\r\n disabled={true}\r\n value={isLinear ? 1 : 0}\r\n onChange={(val: number) => setIsLinear(val === 1)}\r\n />\r\n <NumberDropdown\r\n className={classes.inputField}\r\n infoLabel={{\r\n label: \"Data Type\",\r\n info: <Body1>We will introduce this functionality soon!</Body1>,\r\n }}\r\n options={[\r\n { label: \"Int\", value: 0 },\r\n { label: \"Float\", value: 1 },\r\n ]}\r\n disabled={true}\r\n value={isFloat ? 1 : 0}\r\n onChange={(val: number) => setFloat(val === 1)}\r\n />\r\n </div>\r\n\r\n {/* Middle Row: Red, Green, Blue, Alpha */}\r\n <div className={classes.inputRow}>\r\n <InputRgbField title=\"Red\" value={color} rgbKey=\"r\" onChange={handleChange} />\r\n <InputRgbField title=\"Green\" value={color} rgbKey=\"g\" onChange={handleChange} />\r\n <InputRgbField title=\"Blue\" value={color} rgbKey=\"b\" onChange={handleChange} />\r\n <InputAlphaField color={color} onChange={handleChange} />\r\n </div>\r\n\r\n {/* Bottom Row: Hue, Saturation, Value */}\r\n <div className={classes.inputRow}>\r\n <InputHsvField title=\"Hue\" value={color} hsvKey=\"h\" max={360} onChange={handleChange} />\r\n <InputHsvField title=\"Saturation\" value={color} hsvKey=\"s\" max={100} scale={100} onChange={handleChange} />\r\n <InputHsvField title=\"Value\" value={color} hsvKey=\"v\" max={100} scale={100} onChange={handleChange} />\r\n </div>\r\n\r\n <div className={classes.inputRow}>\r\n <InputHexField title=\"Hexadecimal\" linearHex={isLinear} isLinearMode={isLinear} value={color} onChange={handleChange} />\r\n </div>\r\n </div>\r\n </PopoverSurface>\r\n </Popover>\r\n );\r\n};\r\n\r\nconst HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8})$/);\r\n\r\nexport type InputHexProps = PrimitiveProps<Color3 | Color4> & {\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 classes = useColorPickerStyles();\r\n const { title, value, onChange, linearHex, isLinearMode } = props;\r\n\r\n return (\r\n <TextInput\r\n disabled={linearHex ? !isLinearMode : false}\r\n className={classes.inputField}\r\n value={linearHex ? value.toLinearSpace().toHexString() : value.toHexString()}\r\n validator={(val) => val != \"\" && HEX_REGEX.test(val)}\r\n onChange={(val) => (linearHex ? onChange(Color3.FromHexString(val).toGammaSpace()) : onChange(Color3.FromHexString(val)))}\r\n infoLabel={\r\n title\r\n ? {\r\n label: title,\r\n // If not representing a linearHex, no info is needed.\r\n info: !props.linearHex ? undefined : !isLinearMode ? ( // If representing a linear hex but we are in gammaMode, simple message explaining why linearHex is disabled\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 // If representing a linear hex and we are in linearMode, give information about how to use these hex values\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\r\n gamma 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 : undefined\r\n }\r\n />\r\n );\r\n};\r\n\r\ntype RgbKey = \"r\" | \"g\" | \"b\";\r\ntype InputRgbFieldProps = PrimitiveProps<Color3 | Color4> & {\r\n rgbKey: RgbKey;\r\n};\r\n\r\nconst InputRgbField: FunctionComponent<InputRgbFieldProps> = (props) => {\r\n const { value, onChange, title, rgbKey } = props;\r\n const classes = useColorPickerStyles();\r\n\r\n const handleChange = useCallback(\r\n (val: number) => {\r\n const newColor = value.clone();\r\n newColor[rgbKey] = val / 255.0; // Convert to 0-1 range\r\n onChange(newColor);\r\n },\r\n [value, onChange, rgbKey]\r\n );\r\n\r\n return (\r\n <SpinButton\r\n title={title}\r\n infoLabel={title ? { label: title } : undefined}\r\n className={classes.inputField}\r\n min={0}\r\n max={255}\r\n value={Math.round(value[rgbKey] * 255)}\r\n forceInt\r\n onChange={handleChange}\r\n />\r\n );\r\n};\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\r\ntype HsvKey = \"h\" | \"s\" | \"v\";\r\ntype InputHsvFieldProps = PrimitiveProps<Color3 | Color4> & {\r\n hsvKey: HsvKey;\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 { value, title, hsvKey, max, onChange, scale = 1 } = props;\r\n\r\n const classes = useColorPickerStyles();\r\n\r\n const handleChange = useCallback(\r\n (val: number) => {\r\n // Convert current color to HSV, update the new hsv value, then call onChange prop\r\n const hsv = rgbaToHsv(value);\r\n hsv[hsvKey] = val / scale;\r\n let newColor: Color3 | Color4 = Color3.FromHSV(hsv.h, hsv.s, hsv.v);\r\n if (value instanceof Color4) {\r\n newColor = Color4.FromColor3(newColor, value.a ?? 1);\r\n }\r\n props.onChange(newColor);\r\n },\r\n [value, onChange, hsvKey, scale]\r\n );\r\n\r\n return (\r\n <SpinButton\r\n infoLabel={title ? { label: title } : undefined}\r\n title={title}\r\n className={classes.inputField}\r\n min={0}\r\n max={max}\r\n value={Math.round(rgbaToHsv(value)[hsvKey] * scale)}\r\n forceInt\r\n onChange={handleChange}\r\n />\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 { color, onChange } = props;\r\n\r\n const handleChange = useCallback(\r\n (value: number) => {\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 [onChange]\r\n );\r\n\r\n return (\r\n <SpinButton\r\n disabled={color instanceof Color3}\r\n min={0}\r\n max={1}\r\n className={classes.inputField}\r\n value={color instanceof Color3 ? 1 : color.a}\r\n step={0.01}\r\n onChange={handleChange}\r\n infoLabel={{\r\n label: \"Alpha\",\r\n info:\r\n color instanceof Color3 ? (\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 entity's alpha\r\n property directly, either in code via entity.alpha OR via inspector's transparency section.\r\n </>\r\n ) : undefined,\r\n }}\r\n />\r\n );\r\n};\r\n"]}
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 } from \"react\";\r\nimport {\r\n ColorPicker as FluentColorPicker,\r\n ColorSlider,\r\n ColorArea,\r\n AlphaSlider,\r\n Link,\r\n makeStyles,\r\n Popover,\r\n PopoverSurface,\r\n PopoverTrigger,\r\n tokens,\r\n Body1Strong,\r\n ColorSwatch,\r\n Body1,\r\n} from \"@fluentui/react-components\";\r\nimport type { ColorPickerProps as FluentColorPickerProps } from \"@fluentui/react-components\";\r\nimport { Color3, Color4 } from \"core/Maths/math.color\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { SpinButton } from \"./spinButton\";\r\nimport { TextInput } from \"./textInput\";\r\nimport { NumberDropdown } from \"./dropdown\";\r\nimport { ColorHexValidatorFn } from \"./utils\";\r\n\r\nconst useColorPickerStyles = makeStyles({\r\n container: {\r\n width: \"350px\",\r\n display: \"flex\", // becomes a flexbox\r\n flexDirection: \"column\", // with children in a column\r\n alignItems: \"center\", // centers children horizontally\r\n justifyContent: \"center\", // centers children vertically (if height is set)\r\n gap: tokens.spacingVerticalM,\r\n overflow: \"visible\",\r\n },\r\n row: {\r\n flex: 1, // is a row in the container's flex column\r\n display: \"flex\", // becomes its own flexbox\r\n flexDirection: \"row\", // with children in a row\r\n gap: tokens.spacingHorizontalXL,\r\n alignItems: \"center\", // align items vertically\r\n width: \"100%\",\r\n },\r\n colorPicker: {\r\n flex: 1,\r\n width: \"350px\",\r\n height: \"350px\",\r\n },\r\n previewColor: {\r\n width: \"60px\",\r\n height: \"60px\",\r\n borderRadius: tokens.borderRadiusMedium, // 4px?\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 inputRow: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n flex: 1, // grow and fill available space\r\n justifyContent: \"center\",\r\n gap: \"10px\",\r\n width: \"100%\",\r\n },\r\n inputField: {\r\n flex: 1, // grow and fill available space\r\n width: \"auto\",\r\n minWidth: 0,\r\n gap: tokens.spacingVerticalSNudge, // 6px\r\n },\r\n});\r\n\r\nexport type ColorPickerProps<C extends Color3 | Color4> = {\r\n isLinearMode?: boolean;\r\n} & PrimitiveProps<C>;\r\n\r\nexport const ColorPickerPopup: FunctionComponent<ColorPickerProps<Color3 | Color4>> = (props) => {\r\n ColorPickerPopup.displayName = \"ColorPickerPopup\";\r\n const classes = useColorPickerStyles();\r\n const [color, setColor] = useState(props.value);\r\n const [popoverOpen, setPopoverOpen] = useState(false);\r\n const [isLinear, setIsLinear] = useState(props.isLinearMode ?? false);\r\n const [isFloat, setFloat] = useState(false);\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 handleColorPickerChange: 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 handleChange(color);\r\n };\r\n\r\n const handleChange = (newColor: Color3 | Color4) => {\r\n setColor(newColor);\r\n props.onChange(newColor); // Ensures the parent is notified when color changes from within colorPicker\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 <ColorSwatch borderColor={tokens.colorNeutralShadowKeyDarker} size=\"small\" shape=\"rounded\" color={color.toHexString()} value={color.toHexString().slice(1)} />\r\n </PopoverTrigger>\r\n\r\n <PopoverSurface>\r\n <div className={classes.container}>\r\n <FluentColorPicker className={classes.colorPicker} color={rgbaToHsv(color)} onColorChange={handleColorPickerChange}>\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 </FluentColorPicker>\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 <NumberDropdown\r\n className={classes.inputField}\r\n infoLabel={{\r\n label: \"Color Space\",\r\n info: <Body1>Today this is not mutable as the color space is determined by the entity. Soon we will allow swapping</Body1>,\r\n }}\r\n options={[\r\n { label: \"Gamma\", value: 0 },\r\n { label: \"Linear\", value: 1 },\r\n ]}\r\n disabled={true}\r\n value={isLinear ? 1 : 0}\r\n onChange={(val: number) => setIsLinear(val === 1)}\r\n />\r\n <NumberDropdown\r\n className={classes.inputField}\r\n infoLabel={{\r\n label: \"Data Type\",\r\n info: <Body1>We will introduce this functionality soon!</Body1>,\r\n }}\r\n options={[\r\n { label: \"Int\", value: 0 },\r\n { label: \"Float\", value: 1 },\r\n ]}\r\n disabled={true}\r\n value={isFloat ? 1 : 0}\r\n onChange={(val: number) => setFloat(val === 1)}\r\n />\r\n </div>\r\n\r\n {/* Middle Row: Red, Green, Blue, Alpha */}\r\n <div className={classes.inputRow}>\r\n <InputRgbField title=\"Red\" value={color} rgbKey=\"r\" onChange={handleChange} />\r\n <InputRgbField title=\"Green\" value={color} rgbKey=\"g\" onChange={handleChange} />\r\n <InputRgbField title=\"Blue\" value={color} rgbKey=\"b\" onChange={handleChange} />\r\n <InputAlphaField color={color} onChange={handleChange} />\r\n </div>\r\n\r\n {/* Bottom Row: Hue, Saturation, Value */}\r\n <div className={classes.inputRow}>\r\n <InputHsvField title=\"Hue\" value={color} hsvKey=\"h\" max={360} onChange={handleChange} />\r\n <InputHsvField title=\"Saturation\" value={color} hsvKey=\"s\" max={100} scale={100} onChange={handleChange} />\r\n <InputHsvField title=\"Value\" value={color} hsvKey=\"v\" max={100} scale={100} onChange={handleChange} />\r\n </div>\r\n\r\n <div className={classes.inputRow}>\r\n <InputHexField title=\"Hexadecimal\" linearHex={isLinear} isLinearMode={isLinear} value={color} onChange={handleChange} />\r\n </div>\r\n </div>\r\n </PopoverSurface>\r\n </Popover>\r\n );\r\n};\r\n\r\nexport type InputHexProps = PrimitiveProps<Color3 | Color4> & {\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 classes = useColorPickerStyles();\r\n const { title, value, onChange, linearHex, isLinearMode } = props;\r\n\r\n return (\r\n <TextInput\r\n disabled={linearHex ? !isLinearMode : false}\r\n className={classes.inputField}\r\n value={linearHex ? value.toLinearSpace().toHexString() : value.toHexString()}\r\n validator={ColorHexValidatorFn}\r\n onChange={(val) => (linearHex ? onChange(Color3.FromHexString(val).toGammaSpace()) : onChange(Color3.FromHexString(val)))}\r\n infoLabel={\r\n title\r\n ? {\r\n label: title,\r\n // If not representing a linearHex, no info is needed.\r\n info: !props.linearHex ? undefined : !isLinearMode ? ( // If representing a linear hex but we are in gammaMode, simple message explaining why linearHex is disabled\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 // If representing a linear hex and we are in linearMode, give information about how to use these hex values\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\r\n gamma 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 : undefined\r\n }\r\n />\r\n );\r\n};\r\n\r\ntype RgbKey = \"r\" | \"g\" | \"b\";\r\ntype InputRgbFieldProps = PrimitiveProps<Color3 | Color4> & {\r\n rgbKey: RgbKey;\r\n};\r\n\r\nconst InputRgbField: FunctionComponent<InputRgbFieldProps> = (props) => {\r\n const { value, onChange, title, rgbKey } = props;\r\n const classes = useColorPickerStyles();\r\n\r\n const handleChange = useCallback(\r\n (val: number) => {\r\n const newColor = value.clone();\r\n newColor[rgbKey] = val / 255.0; // Convert to 0-1 range\r\n onChange(newColor);\r\n },\r\n [value, onChange, rgbKey]\r\n );\r\n\r\n return (\r\n <SpinButton\r\n title={title}\r\n infoLabel={title ? { label: title } : undefined}\r\n className={classes.inputField}\r\n min={0}\r\n max={255}\r\n value={Math.round(value[rgbKey] * 255)}\r\n forceInt\r\n onChange={handleChange}\r\n />\r\n );\r\n};\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\r\ntype HsvKey = \"h\" | \"s\" | \"v\";\r\ntype InputHsvFieldProps = PrimitiveProps<Color3 | Color4> & {\r\n hsvKey: HsvKey;\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 { value, title, hsvKey, max, onChange, scale = 1 } = props;\r\n\r\n const classes = useColorPickerStyles();\r\n\r\n const handleChange = useCallback(\r\n (val: number) => {\r\n // Convert current color to HSV, update the new hsv value, then call onChange prop\r\n const hsv = rgbaToHsv(value);\r\n hsv[hsvKey] = val / scale;\r\n let newColor: Color3 | Color4 = Color3.FromHSV(hsv.h, hsv.s, hsv.v);\r\n if (value instanceof Color4) {\r\n newColor = Color4.FromColor3(newColor, value.a ?? 1);\r\n }\r\n props.onChange(newColor);\r\n },\r\n [value, onChange, hsvKey, scale]\r\n );\r\n\r\n return (\r\n <SpinButton\r\n infoLabel={title ? { label: title } : undefined}\r\n title={title}\r\n className={classes.inputField}\r\n min={0}\r\n max={max}\r\n value={Math.round(rgbaToHsv(value)[hsvKey] * scale)}\r\n forceInt\r\n onChange={handleChange}\r\n />\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 { color, onChange } = props;\r\n\r\n const handleChange = useCallback(\r\n (value: number) => {\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 [onChange]\r\n );\r\n\r\n return (\r\n <SpinButton\r\n disabled={color instanceof Color3}\r\n min={0}\r\n max={1}\r\n className={classes.inputField}\r\n value={color instanceof Color3 ? 1 : color.a}\r\n step={0.01}\r\n onChange={handleChange}\r\n infoLabel={{\r\n label: \"Alpha\",\r\n info:\r\n color instanceof Color3 ? (\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 entity's alpha\r\n property directly, either in code via entity.alpha OR via inspector's transparency section.\r\n </>\r\n ) : undefined,\r\n }}\r\n />\r\n );\r\n};\r\n"]}
@@ -11,16 +11,3 @@ export type SpinButtonProps = PrimitiveProps<number> & {
11
11
  validator?: (value: number) => boolean;
12
12
  };
13
13
  export declare const SpinButton: FunctionComponent<SpinButtonProps>;
14
- /**
15
- * Fluent's CalculatePrecision function
16
- * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L91C1
17
- *
18
- * Calculates a number's precision based on the number of trailing
19
- * zeros if the number does not have a decimal indicated by a negative
20
- * precision. Otherwise, it calculates the number of digits after
21
- * the decimal point indicated by a positive precision.
22
- *
23
- * @param value - the value to determine the precision of
24
- * @returns the calculated precision
25
- */
26
- export declare function CalculatePrecision(value: number): number;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { SpinButton as FluentSpinButton, mergeClasses, useId } from "@fluentui/react-components";
3
3
  import { useEffect, useState, useRef } from "react";
4
4
  import { InfoLabel } from "./infoLabel.js";
5
- import { HandleKeyDown, HandleOnBlur, useInputStyles } from "./utils.js";
5
+ import { CalculatePrecision, HandleKeyDown, HandleOnBlur, useInputStyles } from "./utils.js";
6
6
  export const SpinButton = (props) => {
7
7
  SpinButton.displayName = "SpinButton";
8
8
  const classes = useInputStyles();
@@ -11,6 +11,7 @@ export const SpinButton = (props) => {
11
11
  const lastCommittedValue = useRef(props.value);
12
12
  // step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin
13
13
  const step = props.step != undefined ? props.step : props.forceInt ? 1 : undefined;
14
+ const precision = Math.min(4, step !== undefined ? Math.max(0, CalculatePrecision(step)) : 2); // If no step, set precision to 2. Regardless, cap precision at 4 to avoid wild numbers
14
15
  useEffect(() => {
15
16
  if (props.value !== lastCommittedValue.current) {
16
17
  lastCommittedValue.current = props.value;
@@ -48,49 +49,6 @@ export const SpinButton = (props) => {
48
49
  };
49
50
  const id = useId("spin-button");
50
51
  const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : "", props.className);
51
- return (_jsxs("div", { className: classes.container, children: [props.infoLabel && _jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), _jsx(FluentSpinButton, { ...props, input: { className: classes.inputSlot }, 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 })] }));
52
+ return (_jsxs("div", { className: classes.container, children: [props.infoLabel && _jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), _jsx(FluentSpinButton, { ...props, input: { className: classes.inputSlot }, step: step, id: id, size: "medium", precision: precision, displayValue: `${value.toFixed(precision)}${props.unit ? " " + props.unit : ""}`, value: value, onChange: handleChange, onKeyUp: handleKeyUp, onKeyDown: HandleKeyDown, onBlur: HandleOnBlur, className: mergedClassName })] }));
52
53
  };
53
- /**
54
- * Fluent's CalculatePrecision function
55
- * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L91C1
56
- *
57
- * Calculates a number's precision based on the number of trailing
58
- * zeros if the number does not have a decimal indicated by a negative
59
- * precision. Otherwise, it calculates the number of digits after
60
- * the decimal point indicated by a positive precision.
61
- *
62
- * @param value - the value to determine the precision of
63
- * @returns the calculated precision
64
- */
65
- export function CalculatePrecision(value) {
66
- /**
67
- * Group 1:
68
- * [1-9]([0]+$) matches trailing zeros
69
- * Group 2:
70
- * \.([0-9]*) matches all digits after a decimal point.
71
- */ const groups = /[1-9]([0]+$)|\.([0-9]*)/.exec(String(value));
72
- if (!groups) {
73
- return 0;
74
- }
75
- if (groups[1]) {
76
- return -groups[1].length;
77
- }
78
- if (groups[2]) {
79
- return groups[2].length;
80
- }
81
- return 0;
82
- }
83
- /**
84
- * Fluent's PrecisionRound function
85
- * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L116
86
- *
87
- * Rounds a number to a certain level of precision. Accepts negative precision.
88
- * @param value - The value that is being rounded.
89
- * @param precision - The number of decimal places to round the number to
90
- * @returns The rounded number.
91
- */
92
- function PrecisionRound(value, precision) {
93
- const exp = Math.pow(10, precision);
94
- return Math.round(value * exp) / exp;
95
- }
96
54
  //# sourceMappingURL=spinButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spinButton.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/spinButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import { SpinButton as FluentSpinButton, mergeClasses, useId } from \"@fluentui/react-components\";\r\nimport type { SpinButtonOnChangeData, SpinButtonChangeEvent } from \"@fluentui/react-components\";\r\nimport type { FunctionComponent, KeyboardEvent } from \"react\";\r\nimport { useEffect, useState, useRef } from \"react\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { InfoLabel } from \"./infoLabel\";\r\nimport { HandleKeyDown, HandleOnBlur, useInputStyles } from \"./utils\";\r\n\r\nexport type SpinButtonProps = PrimitiveProps<number> & {\r\n min?: number;\r\n max?: number;\r\n /** Determines how much the spinbutton increments with the arrow keys. Note this also determines the precision value (# of decimals in display value)\r\n * i.e. if step = 1, precision = 0. step = 0.0089, precision = 4. step = 300, precision = 2. step = 23.00, precision = 2. */\r\n step?: number;\r\n unit?: string;\r\n forceInt?: boolean;\r\n validator?: (value: number) => boolean;\r\n};\r\n\r\nexport const SpinButton: FunctionComponent<SpinButtonProps> = (props) => {\r\n SpinButton.displayName = \"SpinButton\";\r\n const classes = useInputStyles();\r\n\r\n const { min, max } = props;\r\n\r\n const [value, setValue] = useState(props.value);\r\n const lastCommittedValue = useRef(props.value);\r\n // step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin\r\n const step = props.step != undefined ? props.step : props.forceInt ? 1 : undefined;\r\n\r\n useEffect(() => {\r\n if (props.value !== lastCommittedValue.current) {\r\n lastCommittedValue.current = props.value;\r\n setValue(props.value); // Update local state when props.value changes\r\n }\r\n }, [props.value]);\r\n\r\n const validateValue = (numericValue: number): boolean => {\r\n const outOfBounds = (min !== undefined && numericValue < min) || (max !== undefined && numericValue > max);\r\n const failsValidator = props.validator && !props.validator(numericValue);\r\n const failsIntCheck = props.forceInt ? !Number.isInteger(numericValue) : false;\r\n const invalid = !!outOfBounds || !!failsValidator || isNaN(numericValue) || !!failsIntCheck;\r\n return !invalid;\r\n };\r\n\r\n const tryCommitValue = (currVal: number) => {\r\n // Only commit if valid and different from last committed value\r\n if (validateValue(currVal) && currVal !== lastCommittedValue.current) {\r\n lastCommittedValue.current = currVal;\r\n props.onChange(currVal);\r\n }\r\n };\r\n\r\n const handleChange = (event: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n if (data.value != null && !Number.isNaN(data.value)) {\r\n setValue(data.value);\r\n tryCommitValue(data.value);\r\n }\r\n };\r\n\r\n const handleKeyUp = (event: KeyboardEvent<HTMLInputElement>) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n\r\n if (event.key !== \"Enter\") {\r\n const currVal = parseFloat((event.target as any).value); // Cannot use currentTarget.value as it won't have the most recently typed value\r\n setValue(currVal);\r\n tryCommitValue(currVal);\r\n }\r\n };\r\n\r\n const id = useId(\"spin-button\");\r\n const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : \"\", props.className);\r\n\r\n return (\r\n <div className={classes.container}>\r\n {props.infoLabel && <InfoLabel {...props.infoLabel} htmlFor={id} />}\r\n <FluentSpinButton\r\n {...props}\r\n input={{ className: classes.inputSlot }}\r\n step={step}\r\n id={id}\r\n size=\"medium\"\r\n precision={CalculatePrecision(step ?? 1.01)}\r\n displayValue={props.unit ? `${PrecisionRound(value, CalculatePrecision(step ?? 1.01))} ${props.unit}` : undefined}\r\n value={value}\r\n onChange={handleChange}\r\n onKeyUp={handleKeyUp}\r\n onKeyDown={HandleKeyDown}\r\n onBlur={HandleOnBlur}\r\n className={mergedClassName}\r\n />\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Fluent's CalculatePrecision function\r\n * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L91C1\r\n *\r\n * Calculates a number's precision based on the number of trailing\r\n * zeros if the number does not have a decimal indicated by a negative\r\n * precision. Otherwise, it calculates the number of digits after\r\n * the decimal point indicated by a positive precision.\r\n *\r\n * @param value - the value to determine the precision of\r\n * @returns the calculated precision\r\n */\r\nexport function CalculatePrecision(value: number) {\r\n /**\r\n * Group 1:\r\n * [1-9]([0]+$) matches trailing zeros\r\n * Group 2:\r\n * \\.([0-9]*) matches all digits after a decimal point.\r\n */ const groups = /[1-9]([0]+$)|\\.([0-9]*)/.exec(String(value));\r\n if (!groups) {\r\n return 0;\r\n }\r\n if (groups[1]) {\r\n return -groups[1].length;\r\n }\r\n if (groups[2]) {\r\n return groups[2].length;\r\n }\r\n return 0;\r\n}\r\n/**\r\n * Fluent's PrecisionRound function\r\n * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L116\r\n *\r\n * Rounds a number to a certain level of precision. Accepts negative precision.\r\n * @param value - The value that is being rounded.\r\n * @param precision - The number of decimal places to round the number to\r\n * @returns The rounded number.\r\n */\r\nfunction PrecisionRound(value: number, precision: number) {\r\n const exp = Math.pow(10, precision);\r\n return Math.round(value * exp) / exp;\r\n}\r\n"]}
1
+ {"version":3,"file":"spinButton.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/spinButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import { SpinButton as FluentSpinButton, mergeClasses, useId } from \"@fluentui/react-components\";\r\nimport type { SpinButtonOnChangeData, SpinButtonChangeEvent } from \"@fluentui/react-components\";\r\nimport type { FunctionComponent, KeyboardEvent } from \"react\";\r\nimport { useEffect, useState, useRef } from \"react\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { InfoLabel } from \"./infoLabel\";\r\nimport { CalculatePrecision, HandleKeyDown, HandleOnBlur, useInputStyles } from \"./utils\";\r\n\r\nexport type SpinButtonProps = PrimitiveProps<number> & {\r\n min?: number;\r\n max?: number;\r\n /** Determines how much the spinbutton increments with the arrow keys. Note this also determines the precision value (# of decimals in display value)\r\n * i.e. if step = 1, precision = 0. step = 0.0089, precision = 4. step = 300, precision = 2. step = 23.00, precision = 2. */\r\n step?: number;\r\n unit?: string;\r\n forceInt?: boolean;\r\n validator?: (value: number) => boolean;\r\n};\r\n\r\nexport const SpinButton: FunctionComponent<SpinButtonProps> = (props) => {\r\n SpinButton.displayName = \"SpinButton\";\r\n const classes = useInputStyles();\r\n\r\n const { min, max } = props;\r\n\r\n const [value, setValue] = useState(props.value);\r\n const lastCommittedValue = useRef(props.value);\r\n // step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin\r\n const step = props.step != undefined ? props.step : props.forceInt ? 1 : undefined;\r\n const precision = Math.min(4, step !== undefined ? Math.max(0, CalculatePrecision(step)) : 2); // If no step, set precision to 2. Regardless, cap precision at 4 to avoid wild numbers\r\n\r\n useEffect(() => {\r\n if (props.value !== lastCommittedValue.current) {\r\n lastCommittedValue.current = props.value;\r\n setValue(props.value); // Update local state when props.value changes\r\n }\r\n }, [props.value]);\r\n\r\n const validateValue = (numericValue: number): boolean => {\r\n const outOfBounds = (min !== undefined && numericValue < min) || (max !== undefined && numericValue > max);\r\n const failsValidator = props.validator && !props.validator(numericValue);\r\n const failsIntCheck = props.forceInt ? !Number.isInteger(numericValue) : false;\r\n const invalid = !!outOfBounds || !!failsValidator || isNaN(numericValue) || !!failsIntCheck;\r\n return !invalid;\r\n };\r\n\r\n const tryCommitValue = (currVal: number) => {\r\n // Only commit if valid and different from last committed value\r\n if (validateValue(currVal) && currVal !== lastCommittedValue.current) {\r\n lastCommittedValue.current = currVal;\r\n props.onChange(currVal);\r\n }\r\n };\r\n\r\n const handleChange = (event: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n if (data.value != null && !Number.isNaN(data.value)) {\r\n setValue(data.value);\r\n tryCommitValue(data.value);\r\n }\r\n };\r\n\r\n const handleKeyUp = (event: KeyboardEvent<HTMLInputElement>) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n\r\n if (event.key !== \"Enter\") {\r\n const currVal = parseFloat((event.target as any).value); // Cannot use currentTarget.value as it won't have the most recently typed value\r\n setValue(currVal);\r\n tryCommitValue(currVal);\r\n }\r\n };\r\n\r\n const id = useId(\"spin-button\");\r\n const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : \"\", props.className);\r\n\r\n return (\r\n <div className={classes.container}>\r\n {props.infoLabel && <InfoLabel {...props.infoLabel} htmlFor={id} />}\r\n <FluentSpinButton\r\n {...props}\r\n input={{ className: classes.inputSlot }}\r\n step={step}\r\n id={id}\r\n size=\"medium\"\r\n precision={precision}\r\n displayValue={`${value.toFixed(precision)}${props.unit ? \" \" + props.unit : \"\"}`}\r\n value={value}\r\n onChange={handleChange}\r\n onKeyUp={handleKeyUp}\r\n onKeyDown={HandleKeyDown}\r\n onBlur={HandleOnBlur}\r\n className={mergedClassName}\r\n />\r\n </div>\r\n );\r\n};\r\n"]}
@@ -64,6 +64,6 @@ export const SyncedSliderInput = (props) => {
64
64
  setValue(value);
65
65
  props.onChange(value); // Input always updates immediately
66
66
  };
67
- return (_jsxs("div", { className: classes.container, children: [infoLabel && _jsx(InfoLabel, { ...infoLabel, htmlFor: "syncedSlider" }), _jsxs("div", { id: "syncedSlider", className: classes.syncedSlider, children: [props.min !== undefined && props.max !== undefined && (_jsx(Slider, { ...passthroughProps, className: classes.slider, min: min / step, max: max / step, step: undefined, value: value / step, onChange: handleSliderChange, onPointerDown: handleSliderPointerDown, onPointerUp: handleSliderPointerUp })), _jsx(SpinButton, { ...passthroughProps, value: Math.round(value / step) * step, onChange: handleInputChange, step: props.step })] })] }));
67
+ return (_jsxs("div", { className: classes.container, children: [infoLabel && _jsx(InfoLabel, { ...infoLabel, htmlFor: "syncedSlider" }), _jsxs("div", { id: "syncedSlider", className: classes.syncedSlider, children: [props.min !== undefined && props.max !== undefined && (_jsx(Slider, { ...passthroughProps, className: classes.slider, min: min / step, max: max / step, step: undefined, value: value / step, onChange: handleSliderChange, onPointerDown: handleSliderPointerDown, onPointerUp: handleSliderPointerUp })), _jsx(SpinButton, { ...passthroughProps, value: value, onChange: handleInputChange, step: props.step })] })] }));
68
68
  };
69
69
  //# sourceMappingURL=syncedSlider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"syncedSlider.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/syncedSlider.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { SliderOnChangeData } from \"@fluentui/react-components\";\r\nimport { makeStyles, Slider } from \"@fluentui/react-components\";\r\nimport { SpinButton } from \"./spinButton\";\r\nimport type { ChangeEvent, FunctionComponent } from \"react\";\r\nimport { useEffect, useState, useRef } from \"react\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { InfoLabel } from \"./infoLabel\";\r\nimport { CustomTokens } from \"./utils\";\r\n\r\nconst useSyncedSliderStyles = makeStyles({\r\n container: { display: \"flex\" },\r\n syncedSlider: {\r\n flex: \"1 1 0\",\r\n flexDirection: \"row\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n },\r\n slider: {\r\n minWidth: CustomTokens.sliderMinWidth, // Minimum width for slider to remain usable\r\n maxWidth: CustomTokens.sliderMaxWidth,\r\n },\r\n});\r\n\r\nexport type SyncedSliderProps = PrimitiveProps<number> & {\r\n /** Minimum value for the slider */\r\n min?: number;\r\n /** Maximum value for the slider */\r\n max?: number;\r\n /** Step size for the slider */\r\n step?: number;\r\n /** Displayed in the ux to indicate unit of measurement */\r\n unit?: string;\r\n /** When true, onChange is only called when the user releases the slider, not during drag */\r\n notifyOnlyOnRelease?: boolean;\r\n};\r\n\r\n/**\r\n * Component which synchronizes a slider and an input field, allowing the user to change the value using either control\r\n * @param props\r\n * @returns SyncedSlider component\r\n */\r\nexport const SyncedSliderInput: FunctionComponent<SyncedSliderProps> = (props) => {\r\n SyncedSliderInput.displayName = \"SyncedSliderInput\";\r\n const { infoLabel, ...passthroughProps } = props;\r\n const classes = useSyncedSliderStyles();\r\n const [value, setValue] = useState<number>(props.value);\r\n const pendingValueRef = useRef<number>(undefined);\r\n const isDraggingRef = useRef(false);\r\n\r\n // NOTE: The Fluent slider will add tick marks if the step prop is anything other than undefined.\r\n // To avoid this, we scale the min/max based on the step so we can always make step undefined.\r\n // The actual step size in the Fluent slider is 1 when it is ste to undefined.\r\n const min = props.min ?? 0;\r\n const max = props.max ?? 100;\r\n const step = props.step ?? 1;\r\n\r\n useEffect(() => {\r\n !isDraggingRef.current && setValue(props.value ?? \"\"); // Update local state when props.value changes as long as user is not actively dragging\r\n }, [props.value]);\r\n\r\n const handleSliderChange = (_: ChangeEvent<HTMLInputElement>, data: SliderOnChangeData) => {\r\n const newValue = data.value * step;\r\n setValue(newValue);\r\n\r\n if (props.notifyOnlyOnRelease) {\r\n // Store the value but don't notify parent yet\r\n pendingValueRef.current = newValue;\r\n } else {\r\n // Notify parent as slider changes\r\n props.onChange(newValue);\r\n }\r\n };\r\n\r\n const handleSliderPointerDown = () => {\r\n isDraggingRef.current = true;\r\n };\r\n\r\n const handleSliderPointerUp = () => {\r\n if (props.notifyOnlyOnRelease && isDraggingRef.current && pendingValueRef.current !== undefined) {\r\n props.onChange(pendingValueRef.current);\r\n pendingValueRef.current = undefined;\r\n }\r\n isDraggingRef.current = false;\r\n };\r\n\r\n const handleInputChange = (value: number) => {\r\n setValue(value);\r\n props.onChange(value); // Input always updates immediately\r\n };\r\n\r\n return (\r\n <div className={classes.container}>\r\n {infoLabel && <InfoLabel {...infoLabel} htmlFor={\"syncedSlider\"} />}\r\n <div id=\"syncedSlider\" className={classes.syncedSlider}>\r\n {props.min !== undefined && props.max !== undefined && (\r\n <Slider\r\n {...passthroughProps}\r\n className={classes.slider}\r\n min={min / step}\r\n max={max / step}\r\n step={undefined}\r\n value={value / step}\r\n onChange={handleSliderChange}\r\n onPointerDown={handleSliderPointerDown}\r\n onPointerUp={handleSliderPointerUp}\r\n />\r\n )}\r\n <SpinButton {...passthroughProps} value={Math.round(value / step) * step} onChange={handleInputChange} step={props.step} />\r\n </div>\r\n </div>\r\n );\r\n};\r\n"]}
1
+ {"version":3,"file":"syncedSlider.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/syncedSlider.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { SliderOnChangeData } from \"@fluentui/react-components\";\r\nimport { makeStyles, Slider } from \"@fluentui/react-components\";\r\nimport { SpinButton } from \"./spinButton\";\r\nimport type { ChangeEvent, FunctionComponent } from \"react\";\r\nimport { useEffect, useState, useRef } from \"react\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { InfoLabel } from \"./infoLabel\";\r\nimport { CustomTokens } from \"./utils\";\r\n\r\nconst useSyncedSliderStyles = makeStyles({\r\n container: { display: \"flex\" },\r\n syncedSlider: {\r\n flex: \"1 1 0\",\r\n flexDirection: \"row\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n },\r\n slider: {\r\n minWidth: CustomTokens.sliderMinWidth, // Minimum width for slider to remain usable\r\n maxWidth: CustomTokens.sliderMaxWidth,\r\n },\r\n});\r\n\r\nexport type SyncedSliderProps = PrimitiveProps<number> & {\r\n /** Minimum value for the slider */\r\n min?: number;\r\n /** Maximum value for the slider */\r\n max?: number;\r\n /** Step size for the slider */\r\n step?: number;\r\n /** Displayed in the ux to indicate unit of measurement */\r\n unit?: string;\r\n /** When true, onChange is only called when the user releases the slider, not during drag */\r\n notifyOnlyOnRelease?: boolean;\r\n};\r\n\r\n/**\r\n * Component which synchronizes a slider and an input field, allowing the user to change the value using either control\r\n * @param props\r\n * @returns SyncedSlider component\r\n */\r\nexport const SyncedSliderInput: FunctionComponent<SyncedSliderProps> = (props) => {\r\n SyncedSliderInput.displayName = \"SyncedSliderInput\";\r\n const { infoLabel, ...passthroughProps } = props;\r\n const classes = useSyncedSliderStyles();\r\n const [value, setValue] = useState<number>(props.value);\r\n const pendingValueRef = useRef<number>(undefined);\r\n const isDraggingRef = useRef(false);\r\n\r\n // NOTE: The Fluent slider will add tick marks if the step prop is anything other than undefined.\r\n // To avoid this, we scale the min/max based on the step so we can always make step undefined.\r\n // The actual step size in the Fluent slider is 1 when it is ste to undefined.\r\n const min = props.min ?? 0;\r\n const max = props.max ?? 100;\r\n const step = props.step ?? 1;\r\n\r\n useEffect(() => {\r\n !isDraggingRef.current && setValue(props.value ?? \"\"); // Update local state when props.value changes as long as user is not actively dragging\r\n }, [props.value]);\r\n\r\n const handleSliderChange = (_: ChangeEvent<HTMLInputElement>, data: SliderOnChangeData) => {\r\n const newValue = data.value * step;\r\n setValue(newValue);\r\n\r\n if (props.notifyOnlyOnRelease) {\r\n // Store the value but don't notify parent yet\r\n pendingValueRef.current = newValue;\r\n } else {\r\n // Notify parent as slider changes\r\n props.onChange(newValue);\r\n }\r\n };\r\n\r\n const handleSliderPointerDown = () => {\r\n isDraggingRef.current = true;\r\n };\r\n\r\n const handleSliderPointerUp = () => {\r\n if (props.notifyOnlyOnRelease && isDraggingRef.current && pendingValueRef.current !== undefined) {\r\n props.onChange(pendingValueRef.current);\r\n pendingValueRef.current = undefined;\r\n }\r\n isDraggingRef.current = false;\r\n };\r\n\r\n const handleInputChange = (value: number) => {\r\n setValue(value);\r\n props.onChange(value); // Input always updates immediately\r\n };\r\n\r\n return (\r\n <div className={classes.container}>\r\n {infoLabel && <InfoLabel {...infoLabel} htmlFor={\"syncedSlider\"} />}\r\n <div id=\"syncedSlider\" className={classes.syncedSlider}>\r\n {props.min !== undefined && props.max !== undefined && (\r\n <Slider\r\n {...passthroughProps}\r\n className={classes.slider}\r\n min={min / step}\r\n max={max / step}\r\n step={undefined}\r\n value={value / step}\r\n onChange={handleSliderChange}\r\n onPointerDown={handleSliderPointerDown}\r\n onPointerUp={handleSliderPointerUp}\r\n />\r\n )}\r\n <SpinButton {...passthroughProps} value={value} onChange={handleInputChange} step={props.step} />\r\n </div>\r\n </div>\r\n );\r\n};\r\n"]}
@@ -12,3 +12,17 @@ export declare const UniformWidthStyling: GriffelStyle;
12
12
  export declare const useInputStyles: () => Record<"input" | "container" | "invalid" | "inputSlot", string>;
13
13
  export declare function HandleOnBlur(event: FocusEvent<HTMLInputElement>): void;
14
14
  export declare function HandleKeyDown(event: KeyboardEvent<HTMLInputElement>): void;
15
+ /**
16
+ * Fluent's CalculatePrecision function
17
+ * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L91C1
18
+ *
19
+ * Calculates a number's precision based on the number of trailing
20
+ * zeros if the number does not have a decimal indicated by a negative
21
+ * precision. Otherwise, it calculates the number of digits after
22
+ * the decimal point indicated by a positive precision.
23
+ *
24
+ * @param value - the value to determine the precision of
25
+ * @returns the calculated precision
26
+ */
27
+ export declare function CalculatePrecision(value: number): number;
28
+ export declare function ColorHexValidatorFn(val: string): boolean;
@@ -31,4 +31,38 @@ export function HandleKeyDown(event) {
31
31
  event.preventDefault();
32
32
  }
33
33
  }
34
+ /**
35
+ * Fluent's CalculatePrecision function
36
+ * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L91C1
37
+ *
38
+ * Calculates a number's precision based on the number of trailing
39
+ * zeros if the number does not have a decimal indicated by a negative
40
+ * precision. Otherwise, it calculates the number of digits after
41
+ * the decimal point indicated by a positive precision.
42
+ *
43
+ * @param value - the value to determine the precision of
44
+ * @returns the calculated precision
45
+ */
46
+ export function CalculatePrecision(value) {
47
+ /**
48
+ * Group 1:
49
+ * [1-9]([0]+$) matches trailing zeros
50
+ * Group 2:
51
+ * \.([0-9]*) matches all digits after a decimal point.
52
+ */ const groups = /[1-9]([0]+$)|\.([0-9]*)/.exec(String(value));
53
+ if (!groups) {
54
+ return 0;
55
+ }
56
+ if (groups[1]) {
57
+ return -groups[1].length;
58
+ }
59
+ if (groups[2]) {
60
+ return groups[2].length;
61
+ }
62
+ return 0;
63
+ }
64
+ const HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8})$/);
65
+ export function ColorHexValidatorFn(val) {
66
+ return val != "" && HEX_REGEX.test(val);
67
+ }
34
68
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAKhE,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,UAAU,EAAE,OAAO;IACnB,UAAU,EAAE,MAAM;IAClB,aAAa,EAAE,MAAM;IACrB,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,MAAM;IACtB,gBAAgB,EAAE,MAAM;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAiB,EAAE,KAAK,EAAE,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAC7G,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;IACrC,KAAK,EAAE,mBAAmB;IAC1B,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;IACjC,OAAO,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,0BAA0B,EAAE;IAC/D,SAAS,EAAE;QACP,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,cAAc,EAAE,QAAQ,EAAE,yBAAyB;QACnD,GAAG,EAAE,KAAK;KACb;CACJ,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAC,KAAmC;IAC5D,KAAK,CAAC,eAAe,EAAE,CAAC;IACxB,KAAK,CAAC,cAAc,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAsC;IAChE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,4BAA4B;IAErD,oEAAoE;IACpE,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;QACxB,KAAK,CAAC,cAAc,EAAE,CAAC;IAC3B,CAAC;AACL,CAAC","sourcesContent":["import { makeStyles, tokens } from \"@fluentui/react-components\";\r\nimport type { GriffelStyle } from \"@fluentui/react-components\";\r\n\r\nimport type { KeyboardEvent, FocusEvent } from \"react\";\r\n\r\nexport const CustomTokens = {\r\n inputWidth: \"150px\",\r\n lineHeight: \"36px\",\r\n labelMinWidth: \"50px\",\r\n sliderMinWidth: \"30px\",\r\n sliderMaxWidth: \"80px\",\r\n rightAlignOffset: \"-8px\",\r\n};\r\n\r\nexport const UniformWidthStyling: GriffelStyle = { width: CustomTokens.inputWidth, boxSizing: \"border-box\" };\r\nexport const useInputStyles = makeStyles({\r\n input: UniformWidthStyling,\r\n inputSlot: { textAlign: \"right\" },\r\n invalid: { backgroundColor: tokens.colorPaletteRedBackground2 },\r\n container: {\r\n flex: 1,\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n justifyContent: \"center\", // align items vertically\r\n gap: \"4px\",\r\n },\r\n});\r\n\r\nexport function HandleOnBlur(event: FocusEvent<HTMLInputElement>) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n}\r\n\r\nexport function HandleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\r\n event.stopPropagation(); // Prevent event propagation\r\n\r\n // Prevent Enter key from causing form submission or value reversion\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAKhE,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,UAAU,EAAE,OAAO;IACnB,UAAU,EAAE,MAAM;IAClB,aAAa,EAAE,MAAM;IACrB,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,MAAM;IACtB,gBAAgB,EAAE,MAAM;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAiB,EAAE,KAAK,EAAE,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAC7G,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;IACrC,KAAK,EAAE,mBAAmB;IAC1B,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;IACjC,OAAO,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,0BAA0B,EAAE;IAC/D,SAAS,EAAE;QACP,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,cAAc,EAAE,QAAQ,EAAE,yBAAyB;QACnD,GAAG,EAAE,KAAK;KACb;CACJ,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAC,KAAmC;IAC5D,KAAK,CAAC,eAAe,EAAE,CAAC;IACxB,KAAK,CAAC,cAAc,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAsC;IAChE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,4BAA4B;IAErD,oEAAoE;IACpE,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;QACxB,KAAK,CAAC,cAAc,EAAE,CAAC;IAC3B,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC5C;;;;;OAKG,CAAC,MAAM,MAAM,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,CAAC,CAAC;IACb,CAAC;IACD,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACZ,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7B,CAAC;IACD,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACZ,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,CAAC;AACb,CAAC;AAED,MAAM,SAAS,GAAG,MAAM,CAAC,mDAAmD,CAAC,CAAC;AAC9E,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC3C,OAAO,GAAG,IAAI,EAAE,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { makeStyles, tokens } from \"@fluentui/react-components\";\r\nimport type { GriffelStyle } from \"@fluentui/react-components\";\r\n\r\nimport type { KeyboardEvent, FocusEvent } from \"react\";\r\n\r\nexport const CustomTokens = {\r\n inputWidth: \"150px\",\r\n lineHeight: \"36px\",\r\n labelMinWidth: \"50px\",\r\n sliderMinWidth: \"30px\",\r\n sliderMaxWidth: \"80px\",\r\n rightAlignOffset: \"-8px\",\r\n};\r\n\r\nexport const UniformWidthStyling: GriffelStyle = { width: CustomTokens.inputWidth, boxSizing: \"border-box\" };\r\nexport const useInputStyles = makeStyles({\r\n input: UniformWidthStyling,\r\n inputSlot: { textAlign: \"right\" },\r\n invalid: { backgroundColor: tokens.colorPaletteRedBackground2 },\r\n container: {\r\n flex: 1,\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n justifyContent: \"center\", // align items vertically\r\n gap: \"4px\",\r\n },\r\n});\r\n\r\nexport function HandleOnBlur(event: FocusEvent<HTMLInputElement>) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n}\r\n\r\nexport function HandleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\r\n event.stopPropagation(); // Prevent event propagation\r\n\r\n // Prevent Enter key from causing form submission or value reversion\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n }\r\n}\r\n\r\n/**\r\n * Fluent's CalculatePrecision function\r\n * https://github.com/microsoft/fluentui/blob/dcbf775d37938eacffa37922fc0b43a3cdd5753f/packages/utilities/src/math.ts#L91C1\r\n *\r\n * Calculates a number's precision based on the number of trailing\r\n * zeros if the number does not have a decimal indicated by a negative\r\n * precision. Otherwise, it calculates the number of digits after\r\n * the decimal point indicated by a positive precision.\r\n *\r\n * @param value - the value to determine the precision of\r\n * @returns the calculated precision\r\n */\r\nexport function CalculatePrecision(value: number) {\r\n /**\r\n * Group 1:\r\n * [1-9]([0]+$) matches trailing zeros\r\n * Group 2:\r\n * \\.([0-9]*) matches all digits after a decimal point.\r\n */ const groups = /[1-9]([0]+$)|\\.([0-9]*)/.exec(String(value));\r\n if (!groups) {\r\n return 0;\r\n }\r\n if (groups[1]) {\r\n return -groups[1].length;\r\n }\r\n if (groups[2]) {\r\n return groups[2].length;\r\n }\r\n return 0;\r\n}\r\n\r\nconst HEX_REGEX = RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8})$/);\r\nexport function ColorHexValidatorFn(val: string) {\r\n return val != \"\" && HEX_REGEX.test(val);\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onerjs/shared-ui-components",
3
- "version": "8.28.0",
3
+ "version": "8.28.2",
4
4
  "main": "index.js",
5
5
  "module": "index.js",
6
6
  "types": "index.d.ts",