@xsolla/xui-date-picker 0.225.0 → 0.227.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/web/index.js CHANGED
@@ -663,6 +663,7 @@ var getFixedPlacementStyle = (side, align, container, panel, viewport, offset) =
663
663
  const vertical = align === "center" ? { top: (container.top + container.bottom) / 2 - panel.height / 2 } : align === "end" ? { bottom: viewport.height - container.bottom } : { top: container.top };
664
664
  return { position: "fixed", ...horizontal, ...vertical };
665
665
  };
666
+ var isSegmentKey = (key) => /^[0-9]$/.test(key) || key === "Backspace" || key === "ArrowUp" || key === "ArrowDown" || key === "ArrowLeft" || key === "ArrowRight";
666
667
  var DatePicker = (0, import_react4.forwardRef)(
667
668
  ({
668
669
  onChange,
@@ -727,6 +728,7 @@ var DatePicker = (0, import_react4.forwardRef)(
727
728
  const [activeSegment, setActiveSegment] = (0, import_react4.useState)(null);
728
729
  const [internalChip, setInternalChip] = (0, import_react4.useState)(null);
729
730
  const [parseError, setParseError] = (0, import_react4.useState)(null);
731
+ const [rawText, setRawText] = (0, import_react4.useState)(null);
730
732
  const [fixedPosition, setFixedPosition] = (0, import_react4.useState)(
731
733
  null
732
734
  );
@@ -803,7 +805,7 @@ var DatePicker = (0, import_react4.forwardRef)(
803
805
  (g) => g.day != null || g.month != null || g.year != null
804
806
  );
805
807
  const showMask = hasAnyFilled || focused && isWeb;
806
- const inputValue = chipLabel ?? (showMask ? composed.text : "");
808
+ const inputValue = rawText ?? chipLabel ?? (showMask ? composed.text : "");
807
809
  const showClear = clearable && editable && (hasAnyFilled || !!chipLabel);
808
810
  const orderedSegments = () => composeField().segments;
809
811
  const firstSegmentKey = () => {
@@ -872,6 +874,60 @@ var DatePicker = (0, import_react4.forwardRef)(
872
874
  commitPart(edit.group, edit.type, Number(edit.buffer));
873
875
  setEdit(null);
874
876
  };
877
+ const parseOne = (token) => {
878
+ const trimmed = token.trim();
879
+ if (!trimmed) return null;
880
+ const parsed = (0, import_date_fns.parse)(trimmed, resolvedFormat, /* @__PURE__ */ new Date());
881
+ return (0, import_date_fns.isValid)(parsed) ? parsed : null;
882
+ };
883
+ const parseFieldText = (text) => {
884
+ if (isRange) {
885
+ const [startText, endText] = text.split(RANGE_SEPARATOR);
886
+ const start = parseOne(startText ?? "");
887
+ const end = parseOne(endText ?? "");
888
+ if (!start || endText?.trim() && !end) {
889
+ return {
890
+ error: `Enter a valid date range (${resolvedFormat} - ${resolvedFormat})`
891
+ };
892
+ }
893
+ return { parts: [datePartsFromDate(start), datePartsFromDate(end)] };
894
+ }
895
+ const date = parseOne(text);
896
+ if (!date) return { error: `Enter a valid date (${resolvedFormat})` };
897
+ return { parts: [datePartsFromDate(date)] };
898
+ };
899
+ const isOutOfBounds = (parts) => parts.map(datePartsToDate).some((d) => d instanceof Date && !isWithinBounds(d));
900
+ const commitRawText = (text) => {
901
+ setEdit(null);
902
+ if (!text.trim()) {
903
+ setRawText(null);
904
+ setParseError(null);
905
+ setGroups(propGroups());
906
+ return;
907
+ }
908
+ const result = parseFieldText(text);
909
+ if ("error" in result) {
910
+ setParseError(result.error);
911
+ return;
912
+ }
913
+ if (isOutOfBounds(result.parts)) {
914
+ setParseError("Date must be within the allowed range");
915
+ return;
916
+ }
917
+ setRawText(null);
918
+ setParseError(null);
919
+ setGroups(result.parts);
920
+ emit(result.parts);
921
+ };
922
+ const handleChangeText = (text) => {
923
+ rest.onChangeText?.(text);
924
+ if (!editable) return;
925
+ markDirty();
926
+ setEdit(null);
927
+ setParseError(null);
928
+ setActiveSegment(null);
929
+ setRawText(text);
930
+ };
875
931
  const defaultPart = (type) => {
876
932
  const now = /* @__PURE__ */ new Date();
877
933
  if (type === "day") return now.getDate();
@@ -964,10 +1020,12 @@ var DatePicker = (0, import_react4.forwardRef)(
964
1020
  }
965
1021
  if (!isWeb || !editable) return;
966
1022
  if (e.key === "Enter") {
967
- commitBuffer();
1023
+ if (rawText !== null) commitRawText(rawText);
1024
+ else commitBuffer();
968
1025
  setOpen(false);
969
1026
  return;
970
1027
  }
1028
+ if (rawText !== null && isSegmentKey(e.key)) setRawText(null);
971
1029
  if (e.key === "ArrowUp") return handleArrowStep(e, 1);
972
1030
  if (e.key === "ArrowDown") return handleArrowStep(e, -1);
973
1031
  if (e.key === "ArrowLeft") return handleArrowMove(e, -1);
@@ -1020,30 +1078,33 @@ var DatePicker = (0, import_react4.forwardRef)(
1020
1078
  setParseError(null);
1021
1079
  return;
1022
1080
  }
1081
+ if (rawText !== null) {
1082
+ commitRawText(rawText);
1083
+ return;
1084
+ }
1023
1085
  let next = groups;
1086
+ let rejected = false;
1024
1087
  if (edit) {
1025
1088
  const clamped = clampDatePart(
1026
1089
  edit.type,
1027
1090
  Number(edit.buffer),
1028
1091
  groups[edit.group]
1029
1092
  );
1030
- next = groups.map(
1031
- (g, i) => i === edit.group ? { ...g, [edit.type]: clamped } : g
1032
- );
1093
+ const edited = { ...groups[edit.group], [edit.type]: clamped };
1094
+ const assembled = datePartsToDate(edited);
1095
+ if (assembled && !isWithinBounds(assembled)) {
1096
+ rejected = true;
1097
+ } else {
1098
+ next = groups.map((g, i) => i === edit.group ? edited : g);
1099
+ }
1033
1100
  }
1034
1101
  const props = propGroups();
1035
1102
  next = next.map((g, i) => isDatePartsComplete(g) ? g : props[i]);
1036
1103
  setEdit(null);
1037
- setParseError(null);
1104
+ setParseError(rejected ? "Date must be within the allowed range" : null);
1038
1105
  setGroups(next);
1039
1106
  emit(next);
1040
1107
  };
1041
- const parseOne = (token) => {
1042
- const trimmed = token.trim();
1043
- if (!trimmed) return null;
1044
- const parsed = (0, import_date_fns.parse)(trimmed, resolvedFormat, /* @__PURE__ */ new Date());
1045
- return (0, import_date_fns.isValid)(parsed) ? parsed : null;
1046
- };
1047
1108
  const handlePaste = (e) => {
1048
1109
  onPasteProp?.(e);
1049
1110
  if (e.defaultPrevented) return;
@@ -1051,34 +1112,20 @@ var DatePicker = (0, import_react4.forwardRef)(
1051
1112
  const text = e.clipboardData?.getData("text") ?? "";
1052
1113
  if (!text.trim()) return;
1053
1114
  e.preventDefault();
1054
- let next;
1055
- if (isRange) {
1056
- const [startText, endText] = text.split(RANGE_SEPARATOR);
1057
- const start = parseOne(startText ?? "");
1058
- const end = parseOne(endText ?? "");
1059
- if (!start) {
1060
- setParseError(
1061
- `Enter a valid date range (${resolvedFormat} - ${resolvedFormat})`
1062
- );
1063
- return;
1064
- }
1065
- next = [datePartsFromDate(start), datePartsFromDate(end)];
1066
- } else {
1067
- const date = parseOne(text);
1068
- if (!date) {
1069
- setParseError(`Enter a valid date (${resolvedFormat})`);
1070
- return;
1071
- }
1072
- next = [datePartsFromDate(date)];
1115
+ const result = parseFieldText(text);
1116
+ if ("error" in result) {
1117
+ setParseError(result.error);
1118
+ return;
1073
1119
  }
1074
- const outOfBounds = next.map(datePartsToDate).some((d) => d instanceof Date && !isWithinBounds(d));
1075
- if (outOfBounds) {
1120
+ const next = result.parts;
1121
+ if (isOutOfBounds(next)) {
1076
1122
  setParseError("Date must be within the allowed range");
1077
1123
  return;
1078
1124
  }
1079
1125
  markDirty();
1080
1126
  setParseError(null);
1081
1127
  setEdit(null);
1128
+ setRawText(null);
1082
1129
  setGroups(next);
1083
1130
  emit(next);
1084
1131
  };
@@ -1093,6 +1140,7 @@ var DatePicker = (0, import_react4.forwardRef)(
1093
1140
  sessionRef.current.cleared = true;
1094
1141
  setGroups(next);
1095
1142
  setEdit(null);
1143
+ setRawText(null);
1096
1144
  setParseError(null);
1097
1145
  setInternalChip(null);
1098
1146
  onChipSelect?.(null);
@@ -1112,6 +1160,7 @@ var DatePicker = (0, import_react4.forwardRef)(
1112
1160
  sessionRef.current = { dirty: false, cleared: false, propKey };
1113
1161
  setGroups(propGroups());
1114
1162
  setEdit(null);
1163
+ setRawText(null);
1115
1164
  setParseError(null);
1116
1165
  }, [propKey]);
1117
1166
  (0, import_react4.useEffect)(() => {
@@ -1309,6 +1358,7 @@ var DatePicker = (0, import_react4.forwardRef)(
1309
1358
  onKeyDown: handleKeyDown,
1310
1359
  onClick: handleFieldClick,
1311
1360
  onPaste: handlePaste,
1361
+ onChangeText: handleChangeText,
1312
1362
  iconRight,
1313
1363
  iconLeft,
1314
1364
  extraClear: showClear,