@sustaina/shared-ui 1.52.0 → 1.54.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.
package/dist/index.d.mts CHANGED
@@ -826,6 +826,7 @@ declare const useGridSettingsStore: zustand.UseBoundStore<zustand.StoreApi<UseGr
826
826
 
827
827
  interface IconProps extends React$1.SVGProps<SVGSVGElement> {
828
828
  size?: number | string;
829
+ strokeWidth?: number | string;
829
830
  }
830
831
 
831
832
  declare const AdministrationIcon: React__default.FC<IconProps>;
@@ -1734,8 +1735,9 @@ type InputNumberProps = NumericFormatProps<InputProps> & {
1734
1735
  min?: number;
1735
1736
  max?: number;
1736
1737
  onStepChange?: (value: number) => void;
1738
+ autoFormatDecimal?: boolean;
1737
1739
  };
1738
- declare const InputNumber: ({ customInputProps, showStepper, step, min, max, onStepChange, onValueChange, value, defaultValue, disabled, onBlur, ...props }: InputNumberProps) => react_jsx_runtime.JSX.Element;
1740
+ declare const InputNumber: ({ customInputProps, showStepper, step, min, max, onStepChange, onValueChange, value, defaultValue, disabled, onBlur, isAllowed: isAllowedProp, autoFormatDecimal, decimalScale: decimalScaleProp, fixedDecimalScale: fixedDecimalScaleProp, ...props }: InputNumberProps) => react_jsx_runtime.JSX.Element;
1739
1741
 
1740
1742
  type PermissionAction = "CREATE" | "READ" | "EDIT" | "DELETE" | "NOTIFY" | "CREATE_DRAFT" | "REQUIRE_SITE";
1741
1743
  type PermissionString = `${string}.${PermissionAction}`;
package/dist/index.d.ts CHANGED
@@ -826,6 +826,7 @@ declare const useGridSettingsStore: zustand.UseBoundStore<zustand.StoreApi<UseGr
826
826
 
827
827
  interface IconProps extends React$1.SVGProps<SVGSVGElement> {
828
828
  size?: number | string;
829
+ strokeWidth?: number | string;
829
830
  }
830
831
 
831
832
  declare const AdministrationIcon: React__default.FC<IconProps>;
@@ -1734,8 +1735,9 @@ type InputNumberProps = NumericFormatProps<InputProps> & {
1734
1735
  min?: number;
1735
1736
  max?: number;
1736
1737
  onStepChange?: (value: number) => void;
1738
+ autoFormatDecimal?: boolean;
1737
1739
  };
1738
- declare const InputNumber: ({ customInputProps, showStepper, step, min, max, onStepChange, onValueChange, value, defaultValue, disabled, onBlur, ...props }: InputNumberProps) => react_jsx_runtime.JSX.Element;
1740
+ declare const InputNumber: ({ customInputProps, showStepper, step, min, max, onStepChange, onValueChange, value, defaultValue, disabled, onBlur, isAllowed: isAllowedProp, autoFormatDecimal, decimalScale: decimalScaleProp, fixedDecimalScale: fixedDecimalScaleProp, ...props }: InputNumberProps) => react_jsx_runtime.JSX.Element;
1739
1741
 
1740
1742
  type PermissionAction = "CREATE" | "READ" | "EDIT" | "DELETE" | "NOTIFY" | "CREATE_DRAFT" | "REQUIRE_SITE";
1741
1743
  type PermissionString = `${string}.${PermissionAction}`;
package/dist/index.js CHANGED
@@ -1176,18 +1176,25 @@ var DataEntryIcon = ({ size = "1em", className, ...props }) => /* @__PURE__ */ j
1176
1176
  ]
1177
1177
  }
1178
1178
  );
1179
- var DecreaseIcon = ({ size = "1em", className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
1179
+ var DecreaseIcon = ({
1180
+ size = "1em",
1181
+ strokeWidth = 1.5,
1182
+ className,
1183
+ ...props
1184
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
1180
1185
  "svg",
1181
1186
  {
1182
1187
  xmlns: "http://www.w3.org/2000/svg",
1183
- viewBox: "0 0 9 4",
1184
- fill: "currentColor",
1188
+ viewBox: "0 0 24 24",
1189
+ fill: "none",
1190
+ stroke: "currentColor",
1191
+ strokeWidth,
1192
+ strokeLinecap: "round",
1185
1193
  width: size,
1186
1194
  height: size,
1187
1195
  className,
1188
- "aria-hidden": true,
1189
1196
  ...props,
1190
- children: /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "0.572754", y: "0.441406", width: "7.57659", height: "2.75347", fill: "currentColor" })
1197
+ children: /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "12", x2: "20", y2: "12" })
1191
1198
  }
1192
1199
  );
1193
1200
  var SuiDotsVerticalIcon = ({ size = "1em", className, ...props }) => /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2325,46 +2332,27 @@ var OutlineArrowIcon = ({ size = "1em", className, ...props }) => /* @__PURE__ *
2325
2332
  )
2326
2333
  }
2327
2334
  );
2328
- var PlusIcon = ({ size = "1em", className, ...props }) => /* @__PURE__ */ jsxRuntime.jsxs(
2335
+ var PlusIcon = ({
2336
+ size = "1em",
2337
+ strokeWidth = 1.5,
2338
+ className,
2339
+ ...props
2340
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(
2329
2341
  "svg",
2330
2342
  {
2331
2343
  xmlns: "http://www.w3.org/2000/svg",
2332
- viewBox: "0 0 9 9",
2333
- fill: "currentColor",
2344
+ viewBox: "0 0 24 24",
2345
+ fill: "none",
2346
+ stroke: "currentColor",
2347
+ strokeWidth,
2348
+ strokeLinecap: "round",
2334
2349
  width: size,
2335
2350
  height: size,
2336
2351
  className,
2337
- "aria-hidden": true,
2338
2352
  ...props,
2339
2353
  children: [
2340
- /* @__PURE__ */ jsxRuntime.jsx(
2341
- "path",
2342
- {
2343
- d: "M3.12305 8.23047L3.12305 0.653882L5.87652 0.653882L5.87652 8.23047L3.12305 8.23047Z",
2344
- fill: "currentColor"
2345
- }
2346
- ),
2347
- /* @__PURE__ */ jsxRuntime.jsx(
2348
- "path",
2349
- {
2350
- d: "M3.12305 8.23047L3.12305 0.653882L5.87652 0.653882L5.87652 8.23047L3.12305 8.23047Z",
2351
- fill: "currentColor"
2352
- }
2353
- ),
2354
- /* @__PURE__ */ jsxRuntime.jsx(
2355
- "path",
2356
- {
2357
- d: "M0.710938 3.06641L8.28752 3.06641V5.81988L0.710937 5.81988L0.710938 3.06641Z",
2358
- fill: "currentColor"
2359
- }
2360
- ),
2361
- /* @__PURE__ */ jsxRuntime.jsx(
2362
- "path",
2363
- {
2364
- d: "M0.710938 3.06641L8.28752 3.06641V5.81988L0.710937 5.81988L0.710938 3.06641Z",
2365
- fill: "currentColor"
2366
- }
2367
- )
2354
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "4", x2: "12", y2: "20" }),
2355
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "12", x2: "20", y2: "12" })
2368
2356
  ]
2369
2357
  }
2370
2358
  );
@@ -15869,8 +15857,11 @@ var Input2 = React__namespace.forwardRef(
15869
15857
  }
15870
15858
  );
15871
15859
  Input2.displayName = "Input";
15872
- var createSourceInfo = () => ({
15873
- source: "prop"
15860
+
15861
+ // src/components/inputNumber/helper.ts
15862
+ var createSourceInfo = (event) => ({
15863
+ event,
15864
+ source: event ? "event" : "prop"
15874
15865
  });
15875
15866
  var parseToNumber = (val) => {
15876
15867
  if (typeof val === "number") return val;
@@ -15880,6 +15871,112 @@ var parseToNumber = (val) => {
15880
15871
  }
15881
15872
  return void 0;
15882
15873
  };
15874
+ var truncateToFixed = (num, scale) => {
15875
+ if (scale === 0) return Math.trunc(num).toString();
15876
+ const sign = num < 0 ? "-" : "";
15877
+ const abs = Math.abs(num);
15878
+ const str = abs.toString();
15879
+ const dotIndex = str.indexOf(".");
15880
+ let intPart;
15881
+ let fracPart;
15882
+ if (dotIndex === -1) {
15883
+ intPart = str;
15884
+ fracPart = "";
15885
+ } else {
15886
+ intPart = str.slice(0, dotIndex);
15887
+ fracPart = str.slice(dotIndex + 1, dotIndex + 1 + scale);
15888
+ }
15889
+ fracPart = fracPart.padEnd(scale, "0");
15890
+ return `${sign}${intPart}.${fracPart}`;
15891
+ };
15892
+ var truncateStringToFixed = (str, scale) => {
15893
+ const trimmed = str.trim();
15894
+ if (trimmed === "" || trimmed === "-") return "0" + (scale > 0 ? "." + "0".repeat(scale) : "");
15895
+ const negative = trimmed.startsWith("-");
15896
+ const unsigned = negative ? trimmed.slice(1) : trimmed;
15897
+ const dotIndex = unsigned.indexOf(".");
15898
+ let intPart;
15899
+ let fracPart;
15900
+ if (dotIndex === -1) {
15901
+ intPart = unsigned || "0";
15902
+ fracPart = "";
15903
+ } else {
15904
+ intPart = unsigned.slice(0, dotIndex) || "0";
15905
+ fracPart = unsigned.slice(dotIndex + 1, dotIndex + 1 + scale);
15906
+ }
15907
+ if (scale === 0) return (negative ? "-" : "") + intPart;
15908
+ fracPart = fracPart.padEnd(scale, "0");
15909
+ return (negative ? "-" : "") + intPart + "." + fracPart;
15910
+ };
15911
+ var clamp = (value, min, max) => {
15912
+ if (max !== void 0 && value > max) return max;
15913
+ if (min !== void 0 && value < min) return min;
15914
+ return value;
15915
+ };
15916
+ function useAutoFormatDecimal({
15917
+ enabled,
15918
+ decimalScale,
15919
+ value,
15920
+ defaultValue
15921
+ }) {
15922
+ const blurScale = enabled ? decimalScale ?? 2 : void 0;
15923
+ const isUserEditingRef = React__namespace.useRef(false);
15924
+ const [formattedValue, setFormattedValue] = React__namespace.useState(() => {
15925
+ if (!enabled) return void 0;
15926
+ const scale = decimalScale ?? 2;
15927
+ const initial = parseToNumber(value) ?? parseToNumber(defaultValue);
15928
+ if (initial !== void 0) return truncateToFixed(initial, scale);
15929
+ return void 0;
15930
+ });
15931
+ React__namespace.useEffect(() => {
15932
+ if (!enabled) return;
15933
+ const parsed = parseToNumber(value);
15934
+ if (parsed !== void 0) {
15935
+ if (blurScale !== void 0 && !isUserEditingRef.current) {
15936
+ setFormattedValue(truncateToFixed(parsed, blurScale));
15937
+ }
15938
+ } else if (value === void 0 || value === null || value === "") {
15939
+ setFormattedValue(void 0);
15940
+ }
15941
+ }, [value, enabled, blurScale]);
15942
+ const onEdit = React__namespace.useCallback(
15943
+ (values, sourceInfo) => {
15944
+ if (!enabled || sourceInfo.source !== "event") return;
15945
+ isUserEditingRef.current = true;
15946
+ setFormattedValue(values.value || void 0);
15947
+ },
15948
+ [enabled]
15949
+ );
15950
+ const onBlur = React__namespace.useCallback(
15951
+ (truncatedStr) => {
15952
+ isUserEditingRef.current = false;
15953
+ if (!enabled || blurScale === void 0) return;
15954
+ setFormattedValue(truncatedStr);
15955
+ },
15956
+ [enabled, blurScale]
15957
+ );
15958
+ const resetEditing = React__namespace.useCallback(() => {
15959
+ isUserEditingRef.current = false;
15960
+ }, []);
15961
+ return { formattedValue, blurScale, onEdit, onBlur, resetEditing, setFormattedValue };
15962
+ }
15963
+ function useStepper({ value, step, min, max, disabled, onStep }) {
15964
+ const [changed, setChanged] = React__namespace.useState(false);
15965
+ const changeValue = React__namespace.useCallback(
15966
+ (delta) => {
15967
+ const current = value ?? 0;
15968
+ const clamped = clamp(current + delta, min, max);
15969
+ setChanged(true);
15970
+ onStep(clamped);
15971
+ },
15972
+ [value, max, min, onStep]
15973
+ );
15974
+ const increment = React__namespace.useCallback(() => changeValue(step), [changeValue, step]);
15975
+ const decrement = React__namespace.useCallback(() => changeValue(-step), [changeValue, step]);
15976
+ const isIncrementDisabled = disabled || max !== void 0 && (value ?? 0) >= max;
15977
+ const isDecrementDisabled = disabled || min !== void 0 && (value ?? 0) <= min;
15978
+ return { changed, increment, decrement, isIncrementDisabled, isDecrementDisabled };
15979
+ }
15883
15980
  var InputNumber = ({
15884
15981
  customInputProps,
15885
15982
  showStepper = false,
@@ -15892,58 +15989,106 @@ var InputNumber = ({
15892
15989
  defaultValue,
15893
15990
  disabled,
15894
15991
  onBlur,
15992
+ isAllowed: isAllowedProp,
15993
+ autoFormatDecimal = false,
15994
+ decimalScale: decimalScaleProp,
15995
+ fixedDecimalScale: fixedDecimalScaleProp,
15895
15996
  ...props
15896
15997
  }) => {
15897
15998
  const [internalValue, setInternalValue] = React__namespace.useState(
15898
15999
  () => parseToNumber(value) ?? parseToNumber(defaultValue)
15899
16000
  );
15900
- const [stepperChanged, setStepperChanged] = React__namespace.useState(false);
16001
+ const internalValueRef = React__namespace.useRef(internalValue);
16002
+ const rawValueRef = React__namespace.useRef("");
16003
+ const isBlurClampedRef = React__namespace.useRef(false);
15901
16004
  React__namespace.useEffect(() => {
15902
16005
  const parsed = parseToNumber(value);
15903
- if (parsed !== void 0) setInternalValue(parsed);
16006
+ if (parsed !== void 0) {
16007
+ internalValueRef.current = parsed;
16008
+ setInternalValue(parsed);
16009
+ }
16010
+ isBlurClampedRef.current = false;
15904
16011
  }, [value]);
15905
- const notifyChange = (newValue) => {
15906
- onStepChange?.(newValue);
15907
- onValueChange?.(
15908
- {
15909
- floatValue: newValue,
15910
- formattedValue: String(newValue),
15911
- value: String(newValue)
16012
+ const autoFormat = useAutoFormatDecimal({
16013
+ enabled: autoFormatDecimal,
16014
+ decimalScale: decimalScaleProp,
16015
+ value,
16016
+ defaultValue
16017
+ });
16018
+ const notifyChange = React__namespace.useCallback(
16019
+ (newValue, event) => {
16020
+ internalValueRef.current = newValue;
16021
+ setInternalValue(newValue);
16022
+ onStepChange?.(newValue);
16023
+ onValueChange?.(
16024
+ { floatValue: newValue, formattedValue: String(newValue), value: String(newValue) },
16025
+ createSourceInfo(event)
16026
+ );
16027
+ },
16028
+ [onStepChange, onValueChange]
16029
+ );
16030
+ const stepper = useStepper({
16031
+ value: internalValue,
16032
+ step,
16033
+ min,
16034
+ max,
16035
+ disabled,
16036
+ onStep: React__namespace.useCallback(
16037
+ (clamped) => {
16038
+ setInternalValue(clamped);
16039
+ if (autoFormat.blurScale !== void 0) {
16040
+ autoFormat.setFormattedValue(truncateToFixed(clamped, autoFormat.blurScale));
16041
+ }
16042
+ notifyChange(clamped);
15912
16043
  },
15913
- createSourceInfo()
15914
- );
15915
- };
15916
- const handleValueChange = (values, sourceInfo) => {
15917
- setInternalValue(values.floatValue);
15918
- onValueChange?.(values, sourceInfo);
15919
- if (values.floatValue !== void 0) {
15920
- onStepChange?.(values.floatValue);
15921
- }
15922
- };
15923
- const handleBlur = (event) => {
15924
- onBlur?.(event);
15925
- if (internalValue === void 0) return;
15926
- const clamped = max !== void 0 && internalValue > max ? max : min !== void 0 && internalValue < min ? min : internalValue;
15927
- if (clamped !== internalValue) {
15928
- setInternalValue(clamped);
15929
- notifyChange(clamped);
15930
- }
15931
- };
15932
- const isAllowed = (values) => {
15933
- const { floatValue } = values;
15934
- if (floatValue !== void 0 && max !== void 0 && floatValue > max) return false;
15935
- if (props.isAllowed && !props.isAllowed(values)) return false;
15936
- return true;
15937
- };
15938
- const changeValue = (delta) => {
15939
- const current = internalValue ?? 0;
15940
- const clamped = delta > 0 && max !== void 0 ? Math.min(current + delta, max) : delta < 0 && min !== void 0 ? Math.max(current + delta, min) : current + delta;
15941
- setInternalValue(clamped);
15942
- setStepperChanged(true);
15943
- notifyChange(clamped);
15944
- };
15945
- const isIncrementDisabled = disabled || max !== void 0 && (internalValue ?? 0) >= max;
15946
- const isDecrementDisabled = disabled || min !== void 0 && (internalValue ?? 0) <= min;
16044
+ [autoFormat, notifyChange]
16045
+ )
16046
+ });
16047
+ const handleValueChange = React__namespace.useCallback(
16048
+ (values, sourceInfo) => {
16049
+ internalValueRef.current = values.floatValue;
16050
+ rawValueRef.current = values.value;
16051
+ setInternalValue(values.floatValue);
16052
+ if (sourceInfo.source === "event") {
16053
+ isBlurClampedRef.current = false;
16054
+ }
16055
+ onValueChange?.(values, sourceInfo);
16056
+ if (values.floatValue !== void 0) onStepChange?.(values.floatValue);
16057
+ autoFormat.onEdit(values, sourceInfo);
16058
+ },
16059
+ [onValueChange, onStepChange, autoFormat]
16060
+ );
16061
+ const handleBlur = React__namespace.useCallback(
16062
+ (event) => {
16063
+ onBlur?.(event);
16064
+ const latestValue = internalValueRef.current;
16065
+ if (latestValue === void 0) {
16066
+ autoFormat.resetEditing();
16067
+ return;
16068
+ }
16069
+ const clamped = clamp(latestValue, min, max);
16070
+ const wasClamped = clamped !== latestValue;
16071
+ if (wasClamped) {
16072
+ isBlurClampedRef.current = true;
16073
+ internalValueRef.current = clamped;
16074
+ rawValueRef.current = String(clamped);
16075
+ setInternalValue(clamped);
16076
+ onValueChange?.(
16077
+ { floatValue: clamped, formattedValue: String(clamped), value: String(clamped) },
16078
+ createSourceInfo()
16079
+ );
16080
+ onStepChange?.(clamped);
16081
+ }
16082
+ if (autoFormatDecimal && autoFormat.blurScale !== void 0) {
16083
+ const rawStr = wasClamped ? String(clamped) : rawValueRef.current || "0";
16084
+ autoFormat.onBlur(truncateStringToFixed(rawStr, autoFormat.blurScale));
16085
+ } else {
16086
+ autoFormat.resetEditing();
16087
+ }
16088
+ },
16089
+ [onBlur, autoFormatDecimal, autoFormat, min, max, onValueChange, onStepChange]
16090
+ );
16091
+ const effectiveValue = autoFormat.formattedValue !== void 0 ? autoFormat.formattedValue : isBlurClampedRef.current || stepper.changed || autoFormatDecimal ? internalValue : value;
15947
16092
  const buttonClass = cn(
15948
16093
  "flex items-center justify-center h-3 w-5 transition-colors outline-none",
15949
16094
  "text-neutral-400 hover:text-neutral-600 active:text-neutral-900",
@@ -15953,11 +16098,16 @@ var InputNumber = ({
15953
16098
  reactNumberFormat.NumericFormat,
15954
16099
  {
15955
16100
  customInput: Input2,
15956
- value: stepperChanged ? internalValue : value,
16101
+ value: effectiveValue?.toString(),
15957
16102
  defaultValue,
15958
16103
  onValueChange: handleValueChange,
15959
16104
  onBlur: handleBlur,
15960
- isAllowed,
16105
+ ...isAllowedProp && { isAllowed: isAllowedProp },
16106
+ ...!autoFormatDecimal && {
16107
+ decimalScale: decimalScaleProp,
16108
+ fixedDecimalScale: fixedDecimalScaleProp
16109
+ },
16110
+ ...autoFormat.formattedValue !== void 0 && { valueIsNumericString: true },
15961
16111
  ...props,
15962
16112
  disabled,
15963
16113
  ...customInputProps,
@@ -15966,8 +16116,8 @@ var InputNumber = ({
15966
16116
  "button",
15967
16117
  {
15968
16118
  type: "button",
15969
- onClick: () => changeValue(step),
15970
- disabled: isIncrementDisabled,
16119
+ onClick: stepper.increment,
16120
+ disabled: stepper.isIncrementDisabled,
15971
16121
  className: buttonClass,
15972
16122
  tabIndex: -1,
15973
16123
  "aria-label": "Increment",
@@ -15978,8 +16128,8 @@ var InputNumber = ({
15978
16128
  "button",
15979
16129
  {
15980
16130
  type: "button",
15981
- onClick: () => changeValue(-step),
15982
- disabled: isDecrementDisabled,
16131
+ onClick: stepper.decrement,
16132
+ disabled: stepper.isDecrementDisabled,
15983
16133
  className: buttonClass,
15984
16134
  tabIndex: -1,
15985
16135
  "aria-label": "Decrement",