@react-stately/utils 3.10.7 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,9 +24,15 @@ $parcel$export(module.exports, "toFixedNumber", () => $ac8e4d4816275668$export$b
24
24
  }
25
25
  function $ac8e4d4816275668$export$e1a7b8e69ef6c52f(value, step) {
26
26
  let roundedValue = value;
27
+ let precision = 0;
27
28
  let stepString = step.toString();
28
- let pointIndex = stepString.indexOf('.');
29
- let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;
29
+ // Handle negative exponents in exponential notation (e.g., "1e-7" → precision 8)
30
+ let eIndex = stepString.toLowerCase().indexOf('e-');
31
+ if (eIndex > 0) precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + eIndex;
32
+ else {
33
+ let pointIndex = stepString.indexOf('.');
34
+ if (pointIndex >= 0) precision = stepString.length - pointIndex;
35
+ }
30
36
  if (precision > 0) {
31
37
  let pow = Math.pow(10, precision);
32
38
  roundedValue = Math.round(roundedValue * pow) / pow;
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;AAAA;;;;;;;;;;CAUC,GAED;;CAEC,GACM,SAAS,0CAAM,KAAa,EAAE,MAAc,CAAC,QAAQ,EAAE,MAAc,QAAQ;IAClF,IAAI,WAAW,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,MAAM;IAC9C,OAAO;AACT;AAEO,SAAS,0CAAqB,KAAa,EAAE,IAAY;IAC9D,IAAI,eAAe;IACnB,IAAI,aAAa,KAAK,QAAQ;IAC9B,IAAI,aAAa,WAAW,OAAO,CAAC;IACpC,IAAI,YAAY,cAAc,IAAI,WAAW,MAAM,GAAG,aAAa;IACnE,IAAI,YAAY,GAAG;QACjB,IAAI,MAAM,KAAK,GAAG,CAAC,IAAI;QACvB,eAAe,KAAK,KAAK,CAAC,eAAe,OAAO;IAClD;IACA,OAAO;AACT;AAEO,SAAS,0CAAgB,KAAa,EAAE,GAAuB,EAAE,GAAuB,EAAE,IAAY;IAC3G,MAAM,OAAO;IACb,MAAM,OAAO;IACb,IAAI,YAAa,AAAC,CAAA,QAAS,CAAA,MAAM,OAAO,IAAI,GAAE,CAAC,IAAK;IACpD,IAAI,eAAe,0CAAqB,KAAK,GAAG,CAAC,aAAa,KAAK,OAC/D,QAAQ,KAAK,IAAI,CAAC,aAAc,CAAA,OAAO,KAAK,GAAG,CAAC,UAAS,IACzD,QAAQ,WAAW;IAEvB,IAAI,CAAC,MAAM,MAAM;QACf,IAAI,eAAe,KACjB,eAAe;aACV,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,MAAM,KAAK,KAAK,CAAC,0CAAqB,AAAC,CAAA,MAAM,GAAE,IAAK,MAAM,SAAS;IAEtF,OAAO,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,KAAK,KAAK,CAAC,0CAAqB,MAAM,MAAM,SAAS;IAGtE,gEAAgE;IAChE,eAAe,0CAAqB,cAAc;IAElD,OAAO;AACT;AAGO,SAAS,yCAAc,KAAa,EAAE,MAAc,EAAE,OAAe,EAAE;IAC5E,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM;IAE3B,OAAO,KAAK,KAAK,CAAC,QAAQ,OAAO;AACnC","sources":["packages/@react-stately/utils/src/number.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Takes a value and forces it to the closest min/max if it's outside. Also forces it to the closest valid step.\n */\nexport function clamp(value: number, min: number = -Infinity, max: number = Infinity): number {\n let newValue = Math.min(Math.max(value, min), max);\n return newValue;\n}\n\nexport function roundToStepPrecision(value: number, step: number): number {\n let roundedValue = value;\n let stepString = step.toString();\n let pointIndex = stepString.indexOf('.');\n let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;\n if (precision > 0) {\n let pow = Math.pow(10, precision);\n roundedValue = Math.round(roundedValue * pow) / pow;\n }\n return roundedValue;\n}\n\nexport function snapValueToStep(value: number, min: number | undefined, max: number | undefined, step: number): number {\n min = Number(min);\n max = Number(max);\n let remainder = ((value - (isNaN(min) ? 0 : min)) % step);\n let snappedValue = roundToStepPrecision(Math.abs(remainder) * 2 >= step\n ? value + Math.sign(remainder) * (step - Math.abs(remainder))\n : value - remainder, step);\n\n if (!isNaN(min)) {\n if (snappedValue < min) {\n snappedValue = min;\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step;\n }\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = Math.floor(roundToStepPrecision(max / step, step)) * step;\n }\n\n // correct floating point behavior by rounding to step precision\n snappedValue = roundToStepPrecision(snappedValue, step);\n\n return snappedValue;\n}\n\n/* Takes a value and rounds off to the number of digits. */\nexport function toFixedNumber(value: number, digits: number, base: number = 10): number {\n const pow = Math.pow(base, digits);\n\n return Math.round(value * pow) / pow;\n}\n"],"names":[],"version":3,"file":"number.main.js.map"}
1
+ {"mappings":";;;;;;;;AAAA;;;;;;;;;;CAUC,GAED;;CAEC,GACM,SAAS,0CAAM,KAAa,EAAE,MAAc,CAAC,QAAQ,EAAE,MAAc,QAAQ;IAClF,IAAI,WAAW,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,MAAM;IAC9C,OAAO;AACT;AAEO,SAAS,0CAAqB,KAAa,EAAE,IAAY;IAC9D,IAAI,eAAe;IACnB,IAAI,YAAY;IAChB,IAAI,aAAa,KAAK,QAAQ;IAC9B,iFAAiF;IACjF,IAAI,SAAS,WAAW,WAAW,GAAG,OAAO,CAAC;IAC9C,IAAI,SAAS,GACX,YAAY,KAAK,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,WAAW;SAC1D;QACL,IAAI,aAAa,WAAW,OAAO,CAAC;QACpC,IAAI,cAAc,GAChB,YAAY,WAAW,MAAM,GAAG;IAEpC;IACA,IAAI,YAAY,GAAG;QACjB,IAAI,MAAM,KAAK,GAAG,CAAC,IAAI;QACvB,eAAe,KAAK,KAAK,CAAC,eAAe,OAAO;IAClD;IACA,OAAO;AACT;AAEO,SAAS,0CAAgB,KAAa,EAAE,GAAuB,EAAE,GAAuB,EAAE,IAAY;IAC3G,MAAM,OAAO;IACb,MAAM,OAAO;IACb,IAAI,YAAa,AAAC,CAAA,QAAS,CAAA,MAAM,OAAO,IAAI,GAAE,CAAC,IAAK;IACpD,IAAI,eAAe,0CAAqB,KAAK,GAAG,CAAC,aAAa,KAAK,OAC/D,QAAQ,KAAK,IAAI,CAAC,aAAc,CAAA,OAAO,KAAK,GAAG,CAAC,UAAS,IACzD,QAAQ,WAAW;IAEvB,IAAI,CAAC,MAAM,MAAM;QACf,IAAI,eAAe,KACjB,eAAe;aACV,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,MAAM,KAAK,KAAK,CAAC,0CAAqB,AAAC,CAAA,MAAM,GAAE,IAAK,MAAM,SAAS;IAEtF,OAAO,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,KAAK,KAAK,CAAC,0CAAqB,MAAM,MAAM,SAAS;IAGtE,gEAAgE;IAChE,eAAe,0CAAqB,cAAc;IAElD,OAAO;AACT;AAGO,SAAS,yCAAc,KAAa,EAAE,MAAc,EAAE,OAAe,EAAE;IAC5E,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM;IAE3B,OAAO,KAAK,KAAK,CAAC,QAAQ,OAAO;AACnC","sources":["packages/@react-stately/utils/src/number.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Takes a value and forces it to the closest min/max if it's outside. Also forces it to the closest valid step.\n */\nexport function clamp(value: number, min: number = -Infinity, max: number = Infinity): number {\n let newValue = Math.min(Math.max(value, min), max);\n return newValue;\n}\n\nexport function roundToStepPrecision(value: number, step: number): number {\n let roundedValue = value;\n let precision = 0;\n let stepString = step.toString();\n // Handle negative exponents in exponential notation (e.g., \"1e-7\" → precision 8)\n let eIndex = stepString.toLowerCase().indexOf('e-');\n if (eIndex > 0) {\n precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + eIndex;\n } else {\n let pointIndex = stepString.indexOf('.');\n if (pointIndex >= 0) {\n precision = stepString.length - pointIndex;\n }\n }\n if (precision > 0) {\n let pow = Math.pow(10, precision);\n roundedValue = Math.round(roundedValue * pow) / pow;\n }\n return roundedValue;\n}\n\nexport function snapValueToStep(value: number, min: number | undefined, max: number | undefined, step: number): number {\n min = Number(min);\n max = Number(max);\n let remainder = ((value - (isNaN(min) ? 0 : min)) % step);\n let snappedValue = roundToStepPrecision(Math.abs(remainder) * 2 >= step\n ? value + Math.sign(remainder) * (step - Math.abs(remainder))\n : value - remainder, step);\n\n if (!isNaN(min)) {\n if (snappedValue < min) {\n snappedValue = min;\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step;\n }\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = Math.floor(roundToStepPrecision(max / step, step)) * step;\n }\n\n // correct floating point behavior by rounding to step precision\n snappedValue = roundToStepPrecision(snappedValue, step);\n\n return snappedValue;\n}\n\n/* Takes a value and rounds off to the number of digits. */\nexport function toFixedNumber(value: number, digits: number, base: number = 10): number {\n const pow = Math.pow(base, digits);\n\n return Math.round(value * pow) / pow;\n}\n"],"names":[],"version":3,"file":"number.main.js.map"}
package/dist/number.mjs CHANGED
@@ -16,9 +16,15 @@
16
16
  }
17
17
  function $9446cca9a3875146$export$e1a7b8e69ef6c52f(value, step) {
18
18
  let roundedValue = value;
19
+ let precision = 0;
19
20
  let stepString = step.toString();
20
- let pointIndex = stepString.indexOf('.');
21
- let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;
21
+ // Handle negative exponents in exponential notation (e.g., "1e-7" → precision 8)
22
+ let eIndex = stepString.toLowerCase().indexOf('e-');
23
+ if (eIndex > 0) precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + eIndex;
24
+ else {
25
+ let pointIndex = stepString.indexOf('.');
26
+ if (pointIndex >= 0) precision = stepString.length - pointIndex;
27
+ }
22
28
  if (precision > 0) {
23
29
  let pow = Math.pow(10, precision);
24
30
  roundedValue = Math.round(roundedValue * pow) / pow;
@@ -16,9 +16,15 @@
16
16
  }
17
17
  function $9446cca9a3875146$export$e1a7b8e69ef6c52f(value, step) {
18
18
  let roundedValue = value;
19
+ let precision = 0;
19
20
  let stepString = step.toString();
20
- let pointIndex = stepString.indexOf('.');
21
- let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;
21
+ // Handle negative exponents in exponential notation (e.g., "1e-7" → precision 8)
22
+ let eIndex = stepString.toLowerCase().indexOf('e-');
23
+ if (eIndex > 0) precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + eIndex;
24
+ else {
25
+ let pointIndex = stepString.indexOf('.');
26
+ if (pointIndex >= 0) precision = stepString.length - pointIndex;
27
+ }
22
28
  if (precision > 0) {
23
29
  let pow = Math.pow(10, precision);
24
30
  roundedValue = Math.round(roundedValue * pow) / pow;
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;;CAUC,GAED;;CAEC,GACM,SAAS,0CAAM,KAAa,EAAE,MAAc,CAAC,QAAQ,EAAE,MAAc,QAAQ;IAClF,IAAI,WAAW,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,MAAM;IAC9C,OAAO;AACT;AAEO,SAAS,0CAAqB,KAAa,EAAE,IAAY;IAC9D,IAAI,eAAe;IACnB,IAAI,aAAa,KAAK,QAAQ;IAC9B,IAAI,aAAa,WAAW,OAAO,CAAC;IACpC,IAAI,YAAY,cAAc,IAAI,WAAW,MAAM,GAAG,aAAa;IACnE,IAAI,YAAY,GAAG;QACjB,IAAI,MAAM,KAAK,GAAG,CAAC,IAAI;QACvB,eAAe,KAAK,KAAK,CAAC,eAAe,OAAO;IAClD;IACA,OAAO;AACT;AAEO,SAAS,0CAAgB,KAAa,EAAE,GAAuB,EAAE,GAAuB,EAAE,IAAY;IAC3G,MAAM,OAAO;IACb,MAAM,OAAO;IACb,IAAI,YAAa,AAAC,CAAA,QAAS,CAAA,MAAM,OAAO,IAAI,GAAE,CAAC,IAAK;IACpD,IAAI,eAAe,0CAAqB,KAAK,GAAG,CAAC,aAAa,KAAK,OAC/D,QAAQ,KAAK,IAAI,CAAC,aAAc,CAAA,OAAO,KAAK,GAAG,CAAC,UAAS,IACzD,QAAQ,WAAW;IAEvB,IAAI,CAAC,MAAM,MAAM;QACf,IAAI,eAAe,KACjB,eAAe;aACV,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,MAAM,KAAK,KAAK,CAAC,0CAAqB,AAAC,CAAA,MAAM,GAAE,IAAK,MAAM,SAAS;IAEtF,OAAO,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,KAAK,KAAK,CAAC,0CAAqB,MAAM,MAAM,SAAS;IAGtE,gEAAgE;IAChE,eAAe,0CAAqB,cAAc;IAElD,OAAO;AACT;AAGO,SAAS,yCAAc,KAAa,EAAE,MAAc,EAAE,OAAe,EAAE;IAC5E,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM;IAE3B,OAAO,KAAK,KAAK,CAAC,QAAQ,OAAO;AACnC","sources":["packages/@react-stately/utils/src/number.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Takes a value and forces it to the closest min/max if it's outside. Also forces it to the closest valid step.\n */\nexport function clamp(value: number, min: number = -Infinity, max: number = Infinity): number {\n let newValue = Math.min(Math.max(value, min), max);\n return newValue;\n}\n\nexport function roundToStepPrecision(value: number, step: number): number {\n let roundedValue = value;\n let stepString = step.toString();\n let pointIndex = stepString.indexOf('.');\n let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;\n if (precision > 0) {\n let pow = Math.pow(10, precision);\n roundedValue = Math.round(roundedValue * pow) / pow;\n }\n return roundedValue;\n}\n\nexport function snapValueToStep(value: number, min: number | undefined, max: number | undefined, step: number): number {\n min = Number(min);\n max = Number(max);\n let remainder = ((value - (isNaN(min) ? 0 : min)) % step);\n let snappedValue = roundToStepPrecision(Math.abs(remainder) * 2 >= step\n ? value + Math.sign(remainder) * (step - Math.abs(remainder))\n : value - remainder, step);\n\n if (!isNaN(min)) {\n if (snappedValue < min) {\n snappedValue = min;\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step;\n }\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = Math.floor(roundToStepPrecision(max / step, step)) * step;\n }\n\n // correct floating point behavior by rounding to step precision\n snappedValue = roundToStepPrecision(snappedValue, step);\n\n return snappedValue;\n}\n\n/* Takes a value and rounds off to the number of digits. */\nexport function toFixedNumber(value: number, digits: number, base: number = 10): number {\n const pow = Math.pow(base, digits);\n\n return Math.round(value * pow) / pow;\n}\n"],"names":[],"version":3,"file":"number.module.js.map"}
1
+ {"mappings":"AAAA;;;;;;;;;;CAUC,GAED;;CAEC,GACM,SAAS,0CAAM,KAAa,EAAE,MAAc,CAAC,QAAQ,EAAE,MAAc,QAAQ;IAClF,IAAI,WAAW,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,MAAM;IAC9C,OAAO;AACT;AAEO,SAAS,0CAAqB,KAAa,EAAE,IAAY;IAC9D,IAAI,eAAe;IACnB,IAAI,YAAY;IAChB,IAAI,aAAa,KAAK,QAAQ;IAC9B,iFAAiF;IACjF,IAAI,SAAS,WAAW,WAAW,GAAG,OAAO,CAAC;IAC9C,IAAI,SAAS,GACX,YAAY,KAAK,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,WAAW;SAC1D;QACL,IAAI,aAAa,WAAW,OAAO,CAAC;QACpC,IAAI,cAAc,GAChB,YAAY,WAAW,MAAM,GAAG;IAEpC;IACA,IAAI,YAAY,GAAG;QACjB,IAAI,MAAM,KAAK,GAAG,CAAC,IAAI;QACvB,eAAe,KAAK,KAAK,CAAC,eAAe,OAAO;IAClD;IACA,OAAO;AACT;AAEO,SAAS,0CAAgB,KAAa,EAAE,GAAuB,EAAE,GAAuB,EAAE,IAAY;IAC3G,MAAM,OAAO;IACb,MAAM,OAAO;IACb,IAAI,YAAa,AAAC,CAAA,QAAS,CAAA,MAAM,OAAO,IAAI,GAAE,CAAC,IAAK;IACpD,IAAI,eAAe,0CAAqB,KAAK,GAAG,CAAC,aAAa,KAAK,OAC/D,QAAQ,KAAK,IAAI,CAAC,aAAc,CAAA,OAAO,KAAK,GAAG,CAAC,UAAS,IACzD,QAAQ,WAAW;IAEvB,IAAI,CAAC,MAAM,MAAM;QACf,IAAI,eAAe,KACjB,eAAe;aACV,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,MAAM,KAAK,KAAK,CAAC,0CAAqB,AAAC,CAAA,MAAM,GAAE,IAAK,MAAM,SAAS;IAEtF,OAAO,IAAI,CAAC,MAAM,QAAQ,eAAe,KACvC,eAAe,KAAK,KAAK,CAAC,0CAAqB,MAAM,MAAM,SAAS;IAGtE,gEAAgE;IAChE,eAAe,0CAAqB,cAAc;IAElD,OAAO;AACT;AAGO,SAAS,yCAAc,KAAa,EAAE,MAAc,EAAE,OAAe,EAAE;IAC5E,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM;IAE3B,OAAO,KAAK,KAAK,CAAC,QAAQ,OAAO;AACnC","sources":["packages/@react-stately/utils/src/number.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Takes a value and forces it to the closest min/max if it's outside. Also forces it to the closest valid step.\n */\nexport function clamp(value: number, min: number = -Infinity, max: number = Infinity): number {\n let newValue = Math.min(Math.max(value, min), max);\n return newValue;\n}\n\nexport function roundToStepPrecision(value: number, step: number): number {\n let roundedValue = value;\n let precision = 0;\n let stepString = step.toString();\n // Handle negative exponents in exponential notation (e.g., \"1e-7\" → precision 8)\n let eIndex = stepString.toLowerCase().indexOf('e-');\n if (eIndex > 0) {\n precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + eIndex;\n } else {\n let pointIndex = stepString.indexOf('.');\n if (pointIndex >= 0) {\n precision = stepString.length - pointIndex;\n }\n }\n if (precision > 0) {\n let pow = Math.pow(10, precision);\n roundedValue = Math.round(roundedValue * pow) / pow;\n }\n return roundedValue;\n}\n\nexport function snapValueToStep(value: number, min: number | undefined, max: number | undefined, step: number): number {\n min = Number(min);\n max = Number(max);\n let remainder = ((value - (isNaN(min) ? 0 : min)) % step);\n let snappedValue = roundToStepPrecision(Math.abs(remainder) * 2 >= step\n ? value + Math.sign(remainder) * (step - Math.abs(remainder))\n : value - remainder, step);\n\n if (!isNaN(min)) {\n if (snappedValue < min) {\n snappedValue = min;\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step;\n }\n } else if (!isNaN(max) && snappedValue > max) {\n snappedValue = Math.floor(roundToStepPrecision(max / step, step)) * step;\n }\n\n // correct floating point behavior by rounding to step precision\n snappedValue = roundToStepPrecision(snappedValue, step);\n\n return snappedValue;\n}\n\n/* Takes a value and rounds off to the number of digits. */\nexport function toFixedNumber(value: number, digits: number, base: number = 10): number {\n const pow = Math.pow(base, digits);\n\n return Math.round(value * pow) / pow;\n}\n"],"names":[],"version":3,"file":"number.module.js.map"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];
2
- export function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];
1
+ import { SetStateAction } from "react";
2
+ export function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];
3
+ export function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];
3
4
  /**
4
5
  * Takes a value and forces it to the closest min/max if it's outside. Also forces it to the closest valid step.
5
6
  */
@@ -1 +1 @@
1
- {"mappings":"AAcA,mCAAmC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;AAChN,mCAAmC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;ACHhN;;GAEG;AACH,sBAAsB,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,EAAE,GAAG,GAAE,MAAiB,GAAG,MAAM,CAG5F;AAcD,gCAAgC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAsBrH;AAGD,8BAA8B,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAAW,GAAG,MAAM,CAItF","sources":["packages/@react-stately/utils/src/packages/@react-stately/utils/src/useControlledState.ts","packages/@react-stately/utils/src/packages/@react-stately/utils/src/number.ts","packages/@react-stately/utils/src/packages/@react-stately/utils/src/index.ts","packages/@react-stately/utils/src/index.ts"],"sourcesContent":[null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {useControlledState} from './useControlledState';\nexport {clamp, snapValueToStep, toFixedNumber} from './number';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":";AAmBA,mCAAmC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;AAChO,mCAAmC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;ACRhO;;GAEG;AACH,sBAAsB,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,EAAE,GAAG,GAAE,MAAiB,GAAG,MAAM,CAG5F;AAuBD,gCAAgC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAsBrH;AAGD,8BAA8B,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAAW,GAAG,MAAM,CAItF","sources":["packages/@react-stately/utils/src/packages/@react-stately/utils/src/useControlledState.ts","packages/@react-stately/utils/src/packages/@react-stately/utils/src/number.ts","packages/@react-stately/utils/src/packages/@react-stately/utils/src/index.ts","packages/@react-stately/utils/src/index.ts"],"sourcesContent":[null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {useControlledState} from './useControlledState';\nexport {clamp, snapValueToStep, toFixedNumber} from './number';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
@@ -1,6 +1,10 @@
1
1
  var $ecn6s$react = require("react");
2
2
 
3
3
 
4
+ function $parcel$interopDefault(a) {
5
+ return a && a.__esModule ? a.default : a;
6
+ }
7
+
4
8
  function $parcel$export(e, n, v, s) {
5
9
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
6
10
  }
@@ -17,8 +21,14 @@ $parcel$export(module.exports, "useControlledState", () => $8d8fdfab47455712$exp
17
21
  * OF ANY KIND, either express or implied. See the License for the specific language
18
22
  * governing permissions and limitations under the License.
19
23
  */
24
+ var $8d8fdfab47455712$var$_React_useInsertionEffect;
25
+ // Use the earliest effect possible to reset the ref below.
26
+ const $8d8fdfab47455712$var$useEarlyEffect = typeof document !== 'undefined' ? ($8d8fdfab47455712$var$_React_useInsertionEffect = (0, ($parcel$interopDefault($ecn6s$react)))['useInsertionEffect']) !== null && $8d8fdfab47455712$var$_React_useInsertionEffect !== void 0 ? $8d8fdfab47455712$var$_React_useInsertionEffect : (0, ($parcel$interopDefault($ecn6s$react))).useLayoutEffect : ()=>{};
20
27
  function $8d8fdfab47455712$export$40bfa8c7b0832715(value, defaultValue, onChange) {
28
+ // Store the value in both state and a ref. The state value will only be used when uncontrolled.
29
+ // The ref is used to track the most current value, which is passed to the function setState callback.
21
30
  let [stateValue, setStateValue] = (0, $ecn6s$react.useState)(value || defaultValue);
31
+ let valueRef = (0, $ecn6s$react.useRef)(stateValue);
22
32
  let isControlledRef = (0, $ecn6s$react.useRef)(value !== undefined);
23
33
  let isControlled = value !== undefined;
24
34
  (0, $ecn6s$react.useEffect)(()=>{
@@ -28,40 +38,28 @@ function $8d8fdfab47455712$export$40bfa8c7b0832715(value, defaultValue, onChange
28
38
  }, [
29
39
  isControlled
30
40
  ]);
41
+ // After each render, update the ref to the current value.
42
+ // This ensures that the setState callback argument is reset.
43
+ // Note: the effect should not have any dependencies so that controlled values always reset.
31
44
  let currentValue = isControlled ? value : stateValue;
45
+ $8d8fdfab47455712$var$useEarlyEffect(()=>{
46
+ valueRef.current = currentValue;
47
+ });
48
+ let [, forceUpdate] = (0, $ecn6s$react.useReducer)(()=>({}), {});
32
49
  let setValue = (0, $ecn6s$react.useCallback)((value, ...args)=>{
33
- let onChangeCaller = (value, ...onChangeArgs)=>{
34
- if (onChange) {
35
- if (!Object.is(currentValue, value)) onChange(value, ...onChangeArgs);
36
- }
37
- if (!isControlled) // If uncontrolled, mutate the currentValue local variable so that
38
- // calling setState multiple times with the same value only emits onChange once.
39
- // We do not use a ref for this because we specifically _do_ want the value to
40
- // reset every render, and assigning to a ref in render breaks aborted suspended renders.
41
- // eslint-disable-next-line react-hooks/exhaustive-deps
42
- currentValue = value;
43
- };
44
- if (typeof value === 'function') {
45
- if (process.env.NODE_ENV !== 'production') console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');
46
- // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates
47
- // when someone using useControlledState calls setControlledState(myFunc)
48
- // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc
49
- // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning
50
- // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same
51
- let updateFunction = (oldValue, ...functionArgs)=>{
52
- let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);
53
- onChangeCaller(interceptedValue, ...args);
54
- if (!isControlled) return interceptedValue;
55
- return oldValue;
56
- };
57
- setStateValue(updateFunction);
58
- } else {
59
- if (!isControlled) setStateValue(value);
60
- onChangeCaller(value, ...args);
50
+ // @ts-ignore - TS doesn't know that T cannot be a function.
51
+ let newValue = typeof value === 'function' ? value(valueRef.current) : value;
52
+ if (!Object.is(valueRef.current, newValue)) {
53
+ // Update the ref so that the next setState callback has the most recent value.
54
+ valueRef.current = newValue;
55
+ setStateValue(newValue);
56
+ // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value.
57
+ forceUpdate();
58
+ // Trigger onChange. Note that if setState is called multiple times in a single event,
59
+ // onChange will be called for each one instead of only once.
60
+ onChange === null || onChange === void 0 ? void 0 : onChange(newValue, ...args);
61
61
  }
62
62
  }, [
63
- isControlled,
64
- currentValue,
65
63
  onChange
66
64
  ]);
67
65
  return [
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;AAAA;;;;;;;;;;CAUC;AAMM,SAAS,0CAA6B,KAAQ,EAAE,YAAe,EAAE,QAAyC;IAC/G,IAAI,CAAC,YAAY,cAAc,GAAG,CAAA,GAAA,qBAAO,EAAE,SAAS;IAEpD,IAAI,kBAAkB,CAAA,GAAA,mBAAK,EAAE,UAAU;IACvC,IAAI,eAAe,UAAU;IAC7B,CAAA,GAAA,sBAAQ,EAAE;QACR,IAAI,gBAAgB,gBAAgB,OAAO;QAC3C,IAAI,kBAAkB,gBAAgB,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC7D,QAAQ,IAAI,CAAC,CAAC,+BAA+B,EAAE,gBAAgB,eAAe,eAAe,IAAI,EAAE,eAAe,eAAe,eAAe,CAAC,CAAC;QAEpJ,gBAAgB,OAAO,GAAG;IAC5B,GAAG;QAAC;KAAa;IAEjB,IAAI,eAAe,eAAe,QAAQ;IAC1C,IAAI,WAAW,CAAA,GAAA,wBAAU,EAAE,CAAC,OAAO,GAAG;QACpC,IAAI,iBAAiB,CAAC,OAAO,GAAG;YAC9B,IAAI,UACF;gBAAA,IAAI,CAAC,OAAO,EAAE,CAAC,cAAc,QAC3B,SAAS,UAAU;YACrB;YAEF,IAAI,CAAC,cACH,kEAAkE;YAClE,gFAAgF;YAChF,8EAA8E;YAC9E,yFAAyF;YACzF,uDAAuD;YACvD,eAAe;QAEnB;QAEA,IAAI,OAAO,UAAU,YAAY;YAC/B,IAAI,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC3B,QAAQ,IAAI,CAAC;YAEf,oGAAoG;YACpG,yEAAyE;YACzE,kIAAkI;YAClI,iKAAiK;YACjK,yIAAyI;YACzI,IAAI,iBAAiB,CAAC,UAAU,GAAG;gBACjC,IAAI,mBAAmB,MAAM,eAAe,eAAe,aAAa;gBACxE,eAAe,qBAAqB;gBACpC,IAAI,CAAC,cACH,OAAO;gBAET,OAAO;YACT;YACA,cAAc;QAChB,OAAO;YACL,IAAI,CAAC,cACH,cAAc;YAEhB,eAAe,UAAU;QAC3B;IACF,GAAG;QAAC;QAAc;QAAc;KAAS;IAEzC,OAAO;QAAC;QAAc;KAAS;AACjC","sources":["packages/@react-stately/utils/src/useControlledState.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {useCallback, useEffect, useRef, useState} from 'react';\n\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: T, defaultValue: T, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void] {\n let [stateValue, setStateValue] = useState(value || defaultValue);\n\n let isControlledRef = useRef(value !== undefined);\n let isControlled = value !== undefined;\n useEffect(() => {\n let wasControlled = isControlledRef.current;\n if (wasControlled !== isControlled && process.env.NODE_ENV !== 'production') {\n console.warn(`WARN: A component changed from ${wasControlled ? 'controlled' : 'uncontrolled'} to ${isControlled ? 'controlled' : 'uncontrolled'}.`);\n }\n isControlledRef.current = isControlled;\n }, [isControlled]);\n\n let currentValue = isControlled ? value : stateValue;\n let setValue = useCallback((value, ...args) => {\n let onChangeCaller = (value, ...onChangeArgs) => {\n if (onChange) {\n if (!Object.is(currentValue, value)) {\n onChange(value, ...onChangeArgs);\n }\n }\n if (!isControlled) {\n // If uncontrolled, mutate the currentValue local variable so that\n // calling setState multiple times with the same value only emits onChange once.\n // We do not use a ref for this because we specifically _do_ want the value to\n // reset every render, and assigning to a ref in render breaks aborted suspended renders.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n currentValue = value;\n }\n };\n\n if (typeof value === 'function') {\n if (process.env.NODE_ENV !== 'production') {\n console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');\n }\n // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates\n // when someone using useControlledState calls setControlledState(myFunc)\n // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc\n // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning\n // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same\n let updateFunction = (oldValue, ...functionArgs) => {\n let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);\n onChangeCaller(interceptedValue, ...args);\n if (!isControlled) {\n return interceptedValue;\n }\n return oldValue;\n };\n setStateValue(updateFunction);\n } else {\n if (!isControlled) {\n setStateValue(value);\n }\n onChangeCaller(value, ...args);\n }\n }, [isControlled, currentValue, onChange]);\n\n return [currentValue, setValue];\n}\n"],"names":[],"version":3,"file":"useControlledState.main.js.map"}
1
+ {"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;IAMG;AAFJ,2DAA2D;AAC3D,MAAM,uCAA+C,OAAO,aAAa,cACrE,CAAA,kDAAA,CAAA,GAAA,sCAAI,CAAC,CAAC,qBAAqB,cAA3B,6DAAA,kDAA+B,CAAA,GAAA,sCAAI,EAAE,eAAe,GACpD,KAAO;AAIJ,SAAS,0CAA6B,KAAQ,EAAE,YAAe,EAAE,QAAyC;IAC/G,gGAAgG;IAChG,sGAAsG;IACtG,IAAI,CAAC,YAAY,cAAc,GAAG,CAAA,GAAA,qBAAO,EAAE,SAAS;IACpD,IAAI,WAAW,CAAA,GAAA,mBAAK,EAAE;IAEtB,IAAI,kBAAkB,CAAA,GAAA,mBAAK,EAAE,UAAU;IACvC,IAAI,eAAe,UAAU;IAC7B,CAAA,GAAA,sBAAQ,EAAE;QACR,IAAI,gBAAgB,gBAAgB,OAAO;QAC3C,IAAI,kBAAkB,gBAAgB,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC7D,QAAQ,IAAI,CAAC,CAAC,+BAA+B,EAAE,gBAAgB,eAAe,eAAe,IAAI,EAAE,eAAe,eAAe,eAAe,CAAC,CAAC;QAEpJ,gBAAgB,OAAO,GAAG;IAC5B,GAAG;QAAC;KAAa;IAEjB,0DAA0D;IAC1D,6DAA6D;IAC7D,4FAA4F;IAC5F,IAAI,eAAe,eAAe,QAAQ;IAC1C,qCAAe;QACb,SAAS,OAAO,GAAG;IACrB;IAEA,IAAI,GAAG,YAAY,GAAG,CAAA,GAAA,uBAAS,EAAE,IAAO,CAAA,CAAC,CAAA,GAAI,CAAC;IAC9C,IAAI,WAAW,CAAA,GAAA,wBAAU,EAAE,CAAC,OAA0B,GAAG;QACvD,4DAA4D;QAC5D,IAAI,WAAW,OAAO,UAAU,aAAa,MAAM,SAAS,OAAO,IAAI;QACvE,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,WAAW;YAC1C,+EAA+E;YAC/E,SAAS,OAAO,GAAG;YAEnB,cAAc;YAEd,6GAA6G;YAC7G;YAEA,sFAAsF;YACtF,6DAA6D;YAC7D,qBAAA,+BAAA,SAAW,aAAa;QAC1B;IACF,GAAG;QAAC;KAAS;IAEb,OAAO;QAAC;QAAc;KAAS;AACjC","sources":["packages/@react-stately/utils/src/useControlledState.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport React, {SetStateAction, useCallback, useEffect, useReducer, useRef, useState} from 'react';\n\n// Use the earliest effect possible to reset the ref below.\nconst useEarlyEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'\n ? React['useInsertionEffect'] ?? React.useLayoutEffect\n : () => {};\n\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: T, defaultValue: T, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void] {\n // Store the value in both state and a ref. The state value will only be used when uncontrolled.\n // The ref is used to track the most current value, which is passed to the function setState callback.\n let [stateValue, setStateValue] = useState(value || defaultValue);\n let valueRef = useRef(stateValue);\n\n let isControlledRef = useRef(value !== undefined);\n let isControlled = value !== undefined;\n useEffect(() => {\n let wasControlled = isControlledRef.current;\n if (wasControlled !== isControlled && process.env.NODE_ENV !== 'production') {\n console.warn(`WARN: A component changed from ${wasControlled ? 'controlled' : 'uncontrolled'} to ${isControlled ? 'controlled' : 'uncontrolled'}.`);\n }\n isControlledRef.current = isControlled;\n }, [isControlled]);\n\n // After each render, update the ref to the current value.\n // This ensures that the setState callback argument is reset.\n // Note: the effect should not have any dependencies so that controlled values always reset.\n let currentValue = isControlled ? value : stateValue;\n useEarlyEffect(() => {\n valueRef.current = currentValue;\n });\n\n let [, forceUpdate] = useReducer(() => ({}), {});\n let setValue = useCallback((value: SetStateAction<T>, ...args: any[]) => {\n // @ts-ignore - TS doesn't know that T cannot be a function.\n let newValue = typeof value === 'function' ? value(valueRef.current) : value;\n if (!Object.is(valueRef.current, newValue)) {\n // Update the ref so that the next setState callback has the most recent value.\n valueRef.current = newValue;\n\n setStateValue(newValue);\n\n // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value.\n forceUpdate();\n\n // Trigger onChange. Note that if setState is called multiple times in a single event,\n // onChange will be called for each one instead of only once.\n onChange?.(newValue, ...args);\n }\n }, [onChange]);\n\n return [currentValue, setValue];\n}\n"],"names":[],"version":3,"file":"useControlledState.main.js.map"}
@@ -1,4 +1,4 @@
1
- import {useState as $3whtM$useState, useRef as $3whtM$useRef, useEffect as $3whtM$useEffect, useCallback as $3whtM$useCallback} from "react";
1
+ import $3whtM$react, {useState as $3whtM$useState, useRef as $3whtM$useRef, useEffect as $3whtM$useEffect, useReducer as $3whtM$useReducer, useCallback as $3whtM$useCallback} from "react";
2
2
 
3
3
  /*
4
4
  * Copyright 2020 Adobe. All rights reserved.
@@ -11,8 +11,14 @@ import {useState as $3whtM$useState, useRef as $3whtM$useRef, useEffect as $3wht
11
11
  * OF ANY KIND, either express or implied. See the License for the specific language
12
12
  * governing permissions and limitations under the License.
13
13
  */
14
+ var $458b0a5536c1a7cf$var$_React_useInsertionEffect;
15
+ // Use the earliest effect possible to reset the ref below.
16
+ const $458b0a5536c1a7cf$var$useEarlyEffect = typeof document !== 'undefined' ? ($458b0a5536c1a7cf$var$_React_useInsertionEffect = (0, $3whtM$react)['useInsertionEffect']) !== null && $458b0a5536c1a7cf$var$_React_useInsertionEffect !== void 0 ? $458b0a5536c1a7cf$var$_React_useInsertionEffect : (0, $3whtM$react).useLayoutEffect : ()=>{};
14
17
  function $458b0a5536c1a7cf$export$40bfa8c7b0832715(value, defaultValue, onChange) {
18
+ // Store the value in both state and a ref. The state value will only be used when uncontrolled.
19
+ // The ref is used to track the most current value, which is passed to the function setState callback.
15
20
  let [stateValue, setStateValue] = (0, $3whtM$useState)(value || defaultValue);
21
+ let valueRef = (0, $3whtM$useRef)(stateValue);
16
22
  let isControlledRef = (0, $3whtM$useRef)(value !== undefined);
17
23
  let isControlled = value !== undefined;
18
24
  (0, $3whtM$useEffect)(()=>{
@@ -22,40 +28,28 @@ function $458b0a5536c1a7cf$export$40bfa8c7b0832715(value, defaultValue, onChange
22
28
  }, [
23
29
  isControlled
24
30
  ]);
31
+ // After each render, update the ref to the current value.
32
+ // This ensures that the setState callback argument is reset.
33
+ // Note: the effect should not have any dependencies so that controlled values always reset.
25
34
  let currentValue = isControlled ? value : stateValue;
35
+ $458b0a5536c1a7cf$var$useEarlyEffect(()=>{
36
+ valueRef.current = currentValue;
37
+ });
38
+ let [, forceUpdate] = (0, $3whtM$useReducer)(()=>({}), {});
26
39
  let setValue = (0, $3whtM$useCallback)((value, ...args)=>{
27
- let onChangeCaller = (value, ...onChangeArgs)=>{
28
- if (onChange) {
29
- if (!Object.is(currentValue, value)) onChange(value, ...onChangeArgs);
30
- }
31
- if (!isControlled) // If uncontrolled, mutate the currentValue local variable so that
32
- // calling setState multiple times with the same value only emits onChange once.
33
- // We do not use a ref for this because we specifically _do_ want the value to
34
- // reset every render, and assigning to a ref in render breaks aborted suspended renders.
35
- // eslint-disable-next-line react-hooks/exhaustive-deps
36
- currentValue = value;
37
- };
38
- if (typeof value === 'function') {
39
- if (process.env.NODE_ENV !== 'production') console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');
40
- // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates
41
- // when someone using useControlledState calls setControlledState(myFunc)
42
- // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc
43
- // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning
44
- // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same
45
- let updateFunction = (oldValue, ...functionArgs)=>{
46
- let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);
47
- onChangeCaller(interceptedValue, ...args);
48
- if (!isControlled) return interceptedValue;
49
- return oldValue;
50
- };
51
- setStateValue(updateFunction);
52
- } else {
53
- if (!isControlled) setStateValue(value);
54
- onChangeCaller(value, ...args);
40
+ // @ts-ignore - TS doesn't know that T cannot be a function.
41
+ let newValue = typeof value === 'function' ? value(valueRef.current) : value;
42
+ if (!Object.is(valueRef.current, newValue)) {
43
+ // Update the ref so that the next setState callback has the most recent value.
44
+ valueRef.current = newValue;
45
+ setStateValue(newValue);
46
+ // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value.
47
+ forceUpdate();
48
+ // Trigger onChange. Note that if setState is called multiple times in a single event,
49
+ // onChange will be called for each one instead of only once.
50
+ onChange === null || onChange === void 0 ? void 0 : onChange(newValue, ...args);
55
51
  }
56
52
  }, [
57
- isControlled,
58
- currentValue,
59
53
  onChange
60
54
  ]);
61
55
  return [
@@ -1,4 +1,4 @@
1
- import {useState as $3whtM$useState, useRef as $3whtM$useRef, useEffect as $3whtM$useEffect, useCallback as $3whtM$useCallback} from "react";
1
+ import $3whtM$react, {useState as $3whtM$useState, useRef as $3whtM$useRef, useEffect as $3whtM$useEffect, useReducer as $3whtM$useReducer, useCallback as $3whtM$useCallback} from "react";
2
2
 
3
3
  /*
4
4
  * Copyright 2020 Adobe. All rights reserved.
@@ -11,8 +11,14 @@ import {useState as $3whtM$useState, useRef as $3whtM$useRef, useEffect as $3wht
11
11
  * OF ANY KIND, either express or implied. See the License for the specific language
12
12
  * governing permissions and limitations under the License.
13
13
  */
14
+ var $458b0a5536c1a7cf$var$_React_useInsertionEffect;
15
+ // Use the earliest effect possible to reset the ref below.
16
+ const $458b0a5536c1a7cf$var$useEarlyEffect = typeof document !== 'undefined' ? ($458b0a5536c1a7cf$var$_React_useInsertionEffect = (0, $3whtM$react)['useInsertionEffect']) !== null && $458b0a5536c1a7cf$var$_React_useInsertionEffect !== void 0 ? $458b0a5536c1a7cf$var$_React_useInsertionEffect : (0, $3whtM$react).useLayoutEffect : ()=>{};
14
17
  function $458b0a5536c1a7cf$export$40bfa8c7b0832715(value, defaultValue, onChange) {
18
+ // Store the value in both state and a ref. The state value will only be used when uncontrolled.
19
+ // The ref is used to track the most current value, which is passed to the function setState callback.
15
20
  let [stateValue, setStateValue] = (0, $3whtM$useState)(value || defaultValue);
21
+ let valueRef = (0, $3whtM$useRef)(stateValue);
16
22
  let isControlledRef = (0, $3whtM$useRef)(value !== undefined);
17
23
  let isControlled = value !== undefined;
18
24
  (0, $3whtM$useEffect)(()=>{
@@ -22,40 +28,28 @@ function $458b0a5536c1a7cf$export$40bfa8c7b0832715(value, defaultValue, onChange
22
28
  }, [
23
29
  isControlled
24
30
  ]);
31
+ // After each render, update the ref to the current value.
32
+ // This ensures that the setState callback argument is reset.
33
+ // Note: the effect should not have any dependencies so that controlled values always reset.
25
34
  let currentValue = isControlled ? value : stateValue;
35
+ $458b0a5536c1a7cf$var$useEarlyEffect(()=>{
36
+ valueRef.current = currentValue;
37
+ });
38
+ let [, forceUpdate] = (0, $3whtM$useReducer)(()=>({}), {});
26
39
  let setValue = (0, $3whtM$useCallback)((value, ...args)=>{
27
- let onChangeCaller = (value, ...onChangeArgs)=>{
28
- if (onChange) {
29
- if (!Object.is(currentValue, value)) onChange(value, ...onChangeArgs);
30
- }
31
- if (!isControlled) // If uncontrolled, mutate the currentValue local variable so that
32
- // calling setState multiple times with the same value only emits onChange once.
33
- // We do not use a ref for this because we specifically _do_ want the value to
34
- // reset every render, and assigning to a ref in render breaks aborted suspended renders.
35
- // eslint-disable-next-line react-hooks/exhaustive-deps
36
- currentValue = value;
37
- };
38
- if (typeof value === 'function') {
39
- if (process.env.NODE_ENV !== 'production') console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');
40
- // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates
41
- // when someone using useControlledState calls setControlledState(myFunc)
42
- // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc
43
- // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning
44
- // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same
45
- let updateFunction = (oldValue, ...functionArgs)=>{
46
- let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);
47
- onChangeCaller(interceptedValue, ...args);
48
- if (!isControlled) return interceptedValue;
49
- return oldValue;
50
- };
51
- setStateValue(updateFunction);
52
- } else {
53
- if (!isControlled) setStateValue(value);
54
- onChangeCaller(value, ...args);
40
+ // @ts-ignore - TS doesn't know that T cannot be a function.
41
+ let newValue = typeof value === 'function' ? value(valueRef.current) : value;
42
+ if (!Object.is(valueRef.current, newValue)) {
43
+ // Update the ref so that the next setState callback has the most recent value.
44
+ valueRef.current = newValue;
45
+ setStateValue(newValue);
46
+ // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value.
47
+ forceUpdate();
48
+ // Trigger onChange. Note that if setState is called multiple times in a single event,
49
+ // onChange will be called for each one instead of only once.
50
+ onChange === null || onChange === void 0 ? void 0 : onChange(newValue, ...args);
55
51
  }
56
52
  }, [
57
- isControlled,
58
- currentValue,
59
53
  onChange
60
54
  ]);
61
55
  return [
@@ -1 +1 @@
1
- {"mappings":";;AAAA;;;;;;;;;;CAUC;AAMM,SAAS,0CAA6B,KAAQ,EAAE,YAAe,EAAE,QAAyC;IAC/G,IAAI,CAAC,YAAY,cAAc,GAAG,CAAA,GAAA,eAAO,EAAE,SAAS;IAEpD,IAAI,kBAAkB,CAAA,GAAA,aAAK,EAAE,UAAU;IACvC,IAAI,eAAe,UAAU;IAC7B,CAAA,GAAA,gBAAQ,EAAE;QACR,IAAI,gBAAgB,gBAAgB,OAAO;QAC3C,IAAI,kBAAkB,gBAAgB,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC7D,QAAQ,IAAI,CAAC,CAAC,+BAA+B,EAAE,gBAAgB,eAAe,eAAe,IAAI,EAAE,eAAe,eAAe,eAAe,CAAC,CAAC;QAEpJ,gBAAgB,OAAO,GAAG;IAC5B,GAAG;QAAC;KAAa;IAEjB,IAAI,eAAe,eAAe,QAAQ;IAC1C,IAAI,WAAW,CAAA,GAAA,kBAAU,EAAE,CAAC,OAAO,GAAG;QACpC,IAAI,iBAAiB,CAAC,OAAO,GAAG;YAC9B,IAAI,UACF;gBAAA,IAAI,CAAC,OAAO,EAAE,CAAC,cAAc,QAC3B,SAAS,UAAU;YACrB;YAEF,IAAI,CAAC,cACH,kEAAkE;YAClE,gFAAgF;YAChF,8EAA8E;YAC9E,yFAAyF;YACzF,uDAAuD;YACvD,eAAe;QAEnB;QAEA,IAAI,OAAO,UAAU,YAAY;YAC/B,IAAI,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC3B,QAAQ,IAAI,CAAC;YAEf,oGAAoG;YACpG,yEAAyE;YACzE,kIAAkI;YAClI,iKAAiK;YACjK,yIAAyI;YACzI,IAAI,iBAAiB,CAAC,UAAU,GAAG;gBACjC,IAAI,mBAAmB,MAAM,eAAe,eAAe,aAAa;gBACxE,eAAe,qBAAqB;gBACpC,IAAI,CAAC,cACH,OAAO;gBAET,OAAO;YACT;YACA,cAAc;QAChB,OAAO;YACL,IAAI,CAAC,cACH,cAAc;YAEhB,eAAe,UAAU;QAC3B;IACF,GAAG;QAAC;QAAc;QAAc;KAAS;IAEzC,OAAO;QAAC;QAAc;KAAS;AACjC","sources":["packages/@react-stately/utils/src/useControlledState.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {useCallback, useEffect, useRef, useState} from 'react';\n\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: T, defaultValue: T, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void] {\n let [stateValue, setStateValue] = useState(value || defaultValue);\n\n let isControlledRef = useRef(value !== undefined);\n let isControlled = value !== undefined;\n useEffect(() => {\n let wasControlled = isControlledRef.current;\n if (wasControlled !== isControlled && process.env.NODE_ENV !== 'production') {\n console.warn(`WARN: A component changed from ${wasControlled ? 'controlled' : 'uncontrolled'} to ${isControlled ? 'controlled' : 'uncontrolled'}.`);\n }\n isControlledRef.current = isControlled;\n }, [isControlled]);\n\n let currentValue = isControlled ? value : stateValue;\n let setValue = useCallback((value, ...args) => {\n let onChangeCaller = (value, ...onChangeArgs) => {\n if (onChange) {\n if (!Object.is(currentValue, value)) {\n onChange(value, ...onChangeArgs);\n }\n }\n if (!isControlled) {\n // If uncontrolled, mutate the currentValue local variable so that\n // calling setState multiple times with the same value only emits onChange once.\n // We do not use a ref for this because we specifically _do_ want the value to\n // reset every render, and assigning to a ref in render breaks aborted suspended renders.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n currentValue = value;\n }\n };\n\n if (typeof value === 'function') {\n if (process.env.NODE_ENV !== 'production') {\n console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');\n }\n // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates\n // when someone using useControlledState calls setControlledState(myFunc)\n // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc\n // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning\n // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same\n let updateFunction = (oldValue, ...functionArgs) => {\n let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);\n onChangeCaller(interceptedValue, ...args);\n if (!isControlled) {\n return interceptedValue;\n }\n return oldValue;\n };\n setStateValue(updateFunction);\n } else {\n if (!isControlled) {\n setStateValue(value);\n }\n onChangeCaller(value, ...args);\n }\n }, [isControlled, currentValue, onChange]);\n\n return [currentValue, setValue];\n}\n"],"names":[],"version":3,"file":"useControlledState.module.js.map"}
1
+ {"mappings":";;AAAA;;;;;;;;;;CAUC;IAMG;AAFJ,2DAA2D;AAC3D,MAAM,uCAA+C,OAAO,aAAa,cACrE,CAAA,kDAAA,CAAA,GAAA,YAAI,CAAC,CAAC,qBAAqB,cAA3B,6DAAA,kDAA+B,CAAA,GAAA,YAAI,EAAE,eAAe,GACpD,KAAO;AAIJ,SAAS,0CAA6B,KAAQ,EAAE,YAAe,EAAE,QAAyC;IAC/G,gGAAgG;IAChG,sGAAsG;IACtG,IAAI,CAAC,YAAY,cAAc,GAAG,CAAA,GAAA,eAAO,EAAE,SAAS;IACpD,IAAI,WAAW,CAAA,GAAA,aAAK,EAAE;IAEtB,IAAI,kBAAkB,CAAA,GAAA,aAAK,EAAE,UAAU;IACvC,IAAI,eAAe,UAAU;IAC7B,CAAA,GAAA,gBAAQ,EAAE;QACR,IAAI,gBAAgB,gBAAgB,OAAO;QAC3C,IAAI,kBAAkB,gBAAgB,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC7D,QAAQ,IAAI,CAAC,CAAC,+BAA+B,EAAE,gBAAgB,eAAe,eAAe,IAAI,EAAE,eAAe,eAAe,eAAe,CAAC,CAAC;QAEpJ,gBAAgB,OAAO,GAAG;IAC5B,GAAG;QAAC;KAAa;IAEjB,0DAA0D;IAC1D,6DAA6D;IAC7D,4FAA4F;IAC5F,IAAI,eAAe,eAAe,QAAQ;IAC1C,qCAAe;QACb,SAAS,OAAO,GAAG;IACrB;IAEA,IAAI,GAAG,YAAY,GAAG,CAAA,GAAA,iBAAS,EAAE,IAAO,CAAA,CAAC,CAAA,GAAI,CAAC;IAC9C,IAAI,WAAW,CAAA,GAAA,kBAAU,EAAE,CAAC,OAA0B,GAAG;QACvD,4DAA4D;QAC5D,IAAI,WAAW,OAAO,UAAU,aAAa,MAAM,SAAS,OAAO,IAAI;QACvE,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,WAAW;YAC1C,+EAA+E;YAC/E,SAAS,OAAO,GAAG;YAEnB,cAAc;YAEd,6GAA6G;YAC7G;YAEA,sFAAsF;YACtF,6DAA6D;YAC7D,qBAAA,+BAAA,SAAW,aAAa;QAC1B;IACF,GAAG;QAAC;KAAS;IAEb,OAAO;QAAC;QAAc;KAAS;AACjC","sources":["packages/@react-stately/utils/src/useControlledState.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport React, {SetStateAction, useCallback, useEffect, useReducer, useRef, useState} from 'react';\n\n// Use the earliest effect possible to reset the ref below.\nconst useEarlyEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'\n ? React['useInsertionEffect'] ?? React.useLayoutEffect\n : () => {};\n\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];\nexport function useControlledState<T, C = T>(value: T, defaultValue: T, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void] {\n // Store the value in both state and a ref. The state value will only be used when uncontrolled.\n // The ref is used to track the most current value, which is passed to the function setState callback.\n let [stateValue, setStateValue] = useState(value || defaultValue);\n let valueRef = useRef(stateValue);\n\n let isControlledRef = useRef(value !== undefined);\n let isControlled = value !== undefined;\n useEffect(() => {\n let wasControlled = isControlledRef.current;\n if (wasControlled !== isControlled && process.env.NODE_ENV !== 'production') {\n console.warn(`WARN: A component changed from ${wasControlled ? 'controlled' : 'uncontrolled'} to ${isControlled ? 'controlled' : 'uncontrolled'}.`);\n }\n isControlledRef.current = isControlled;\n }, [isControlled]);\n\n // After each render, update the ref to the current value.\n // This ensures that the setState callback argument is reset.\n // Note: the effect should not have any dependencies so that controlled values always reset.\n let currentValue = isControlled ? value : stateValue;\n useEarlyEffect(() => {\n valueRef.current = currentValue;\n });\n\n let [, forceUpdate] = useReducer(() => ({}), {});\n let setValue = useCallback((value: SetStateAction<T>, ...args: any[]) => {\n // @ts-ignore - TS doesn't know that T cannot be a function.\n let newValue = typeof value === 'function' ? value(valueRef.current) : value;\n if (!Object.is(valueRef.current, newValue)) {\n // Update the ref so that the next setState callback has the most recent value.\n valueRef.current = newValue;\n\n setStateValue(newValue);\n\n // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value.\n forceUpdate();\n\n // Trigger onChange. Note that if setState is called multiple times in a single event,\n // onChange will be called for each one instead of only once.\n onChange?.(newValue, ...args);\n }\n }, [onChange]);\n\n return [currentValue, setValue];\n}\n"],"names":[],"version":3,"file":"useControlledState.module.js.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-stately/utils",
3
- "version": "3.10.7",
3
+ "version": "3.11.0",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -34,5 +34,5 @@
34
34
  "publishConfig": {
35
35
  "access": "public"
36
36
  },
37
- "gitHead": "265b4d7f107905ee1c6e87a8af1613ab440a6849"
37
+ "gitHead": "4d838da5bfe36abb35aed166995a9ef63825370f"
38
38
  }
package/src/number.ts CHANGED
@@ -20,9 +20,18 @@ export function clamp(value: number, min: number = -Infinity, max: number = Infi
20
20
 
21
21
  export function roundToStepPrecision(value: number, step: number): number {
22
22
  let roundedValue = value;
23
+ let precision = 0;
23
24
  let stepString = step.toString();
24
- let pointIndex = stepString.indexOf('.');
25
- let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;
25
+ // Handle negative exponents in exponential notation (e.g., "1e-7" → precision 8)
26
+ let eIndex = stepString.toLowerCase().indexOf('e-');
27
+ if (eIndex > 0) {
28
+ precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + eIndex;
29
+ } else {
30
+ let pointIndex = stepString.indexOf('.');
31
+ if (pointIndex >= 0) {
32
+ precision = stepString.length - pointIndex;
33
+ }
34
+ }
26
35
  if (precision > 0) {
27
36
  let pow = Math.pow(10, precision);
28
37
  roundedValue = Math.round(roundedValue * pow) / pow;
@@ -10,12 +10,20 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {useCallback, useEffect, useRef, useState} from 'react';
13
+ import React, {SetStateAction, useCallback, useEffect, useReducer, useRef, useState} from 'react';
14
14
 
15
- export function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];
16
- export function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void];
17
- export function useControlledState<T, C = T>(value: T, defaultValue: T, onChange?: (v: C, ...args: any[]) => void): [T, (value: T, ...args: any[]) => void] {
15
+ // Use the earliest effect possible to reset the ref below.
16
+ const useEarlyEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'
17
+ ? React['useInsertionEffect'] ?? React.useLayoutEffect
18
+ : () => {};
19
+
20
+ export function useControlledState<T, C = T>(value: Exclude<T, undefined>, defaultValue: Exclude<T, undefined> | undefined, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];
21
+ export function useControlledState<T, C = T>(value: Exclude<T, undefined> | undefined, defaultValue: Exclude<T, undefined>, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void];
22
+ export function useControlledState<T, C = T>(value: T, defaultValue: T, onChange?: (v: C, ...args: any[]) => void): [T, (value: SetStateAction<T>, ...args: any[]) => void] {
23
+ // Store the value in both state and a ref. The state value will only be used when uncontrolled.
24
+ // The ref is used to track the most current value, which is passed to the function setState callback.
18
25
  let [stateValue, setStateValue] = useState(value || defaultValue);
26
+ let valueRef = useRef(stateValue);
19
27
 
20
28
  let isControlledRef = useRef(value !== undefined);
21
29
  let isControlled = value !== undefined;
@@ -27,49 +35,32 @@ export function useControlledState<T, C = T>(value: T, defaultValue: T, onChange
27
35
  isControlledRef.current = isControlled;
28
36
  }, [isControlled]);
29
37
 
38
+ // After each render, update the ref to the current value.
39
+ // This ensures that the setState callback argument is reset.
40
+ // Note: the effect should not have any dependencies so that controlled values always reset.
30
41
  let currentValue = isControlled ? value : stateValue;
31
- let setValue = useCallback((value, ...args) => {
32
- let onChangeCaller = (value, ...onChangeArgs) => {
33
- if (onChange) {
34
- if (!Object.is(currentValue, value)) {
35
- onChange(value, ...onChangeArgs);
36
- }
37
- }
38
- if (!isControlled) {
39
- // If uncontrolled, mutate the currentValue local variable so that
40
- // calling setState multiple times with the same value only emits onChange once.
41
- // We do not use a ref for this because we specifically _do_ want the value to
42
- // reset every render, and assigning to a ref in render breaks aborted suspended renders.
43
- // eslint-disable-next-line react-hooks/exhaustive-deps
44
- currentValue = value;
45
- }
46
- };
42
+ useEarlyEffect(() => {
43
+ valueRef.current = currentValue;
44
+ });
45
+
46
+ let [, forceUpdate] = useReducer(() => ({}), {});
47
+ let setValue = useCallback((value: SetStateAction<T>, ...args: any[]) => {
48
+ // @ts-ignore - TS doesn't know that T cannot be a function.
49
+ let newValue = typeof value === 'function' ? value(valueRef.current) : value;
50
+ if (!Object.is(valueRef.current, newValue)) {
51
+ // Update the ref so that the next setState callback has the most recent value.
52
+ valueRef.current = newValue;
53
+
54
+ setStateValue(newValue);
55
+
56
+ // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value.
57
+ forceUpdate();
47
58
 
48
- if (typeof value === 'function') {
49
- if (process.env.NODE_ENV !== 'production') {
50
- console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');
51
- }
52
- // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates
53
- // when someone using useControlledState calls setControlledState(myFunc)
54
- // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc
55
- // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning
56
- // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same
57
- let updateFunction = (oldValue, ...functionArgs) => {
58
- let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);
59
- onChangeCaller(interceptedValue, ...args);
60
- if (!isControlled) {
61
- return interceptedValue;
62
- }
63
- return oldValue;
64
- };
65
- setStateValue(updateFunction);
66
- } else {
67
- if (!isControlled) {
68
- setStateValue(value);
69
- }
70
- onChangeCaller(value, ...args);
59
+ // Trigger onChange. Note that if setState is called multiple times in a single event,
60
+ // onChange will be called for each one instead of only once.
61
+ onChange?.(newValue, ...args);
71
62
  }
72
- }, [isControlled, currentValue, onChange]);
63
+ }, [onChange]);
73
64
 
74
65
  return [currentValue, setValue];
75
66
  }