@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.mjs CHANGED
@@ -622,6 +622,7 @@ var getFixedPlacementStyle = (side, align, container, panel, viewport, offset) =
622
622
  const vertical = align === "center" ? { top: (container.top + container.bottom) / 2 - panel.height / 2 } : align === "end" ? { bottom: viewport.height - container.bottom } : { top: container.top };
623
623
  return { position: "fixed", ...horizontal, ...vertical };
624
624
  };
625
+ var isSegmentKey = (key) => /^[0-9]$/.test(key) || key === "Backspace" || key === "ArrowUp" || key === "ArrowDown" || key === "ArrowLeft" || key === "ArrowRight";
625
626
  var DatePicker = forwardRef(
626
627
  ({
627
628
  onChange,
@@ -686,6 +687,7 @@ var DatePicker = forwardRef(
686
687
  const [activeSegment, setActiveSegment] = useState2(null);
687
688
  const [internalChip, setInternalChip] = useState2(null);
688
689
  const [parseError, setParseError] = useState2(null);
690
+ const [rawText, setRawText] = useState2(null);
689
691
  const [fixedPosition, setFixedPosition] = useState2(
690
692
  null
691
693
  );
@@ -762,7 +764,7 @@ var DatePicker = forwardRef(
762
764
  (g) => g.day != null || g.month != null || g.year != null
763
765
  );
764
766
  const showMask = hasAnyFilled || focused && isWeb;
765
- const inputValue = chipLabel ?? (showMask ? composed.text : "");
767
+ const inputValue = rawText ?? chipLabel ?? (showMask ? composed.text : "");
766
768
  const showClear = clearable && editable && (hasAnyFilled || !!chipLabel);
767
769
  const orderedSegments = () => composeField().segments;
768
770
  const firstSegmentKey = () => {
@@ -831,6 +833,60 @@ var DatePicker = forwardRef(
831
833
  commitPart(edit.group, edit.type, Number(edit.buffer));
832
834
  setEdit(null);
833
835
  };
836
+ const parseOne = (token) => {
837
+ const trimmed = token.trim();
838
+ if (!trimmed) return null;
839
+ const parsed = parse(trimmed, resolvedFormat, /* @__PURE__ */ new Date());
840
+ return isValid(parsed) ? parsed : null;
841
+ };
842
+ const parseFieldText = (text) => {
843
+ if (isRange) {
844
+ const [startText, endText] = text.split(RANGE_SEPARATOR);
845
+ const start = parseOne(startText ?? "");
846
+ const end = parseOne(endText ?? "");
847
+ if (!start || endText?.trim() && !end) {
848
+ return {
849
+ error: `Enter a valid date range (${resolvedFormat} - ${resolvedFormat})`
850
+ };
851
+ }
852
+ return { parts: [datePartsFromDate(start), datePartsFromDate(end)] };
853
+ }
854
+ const date = parseOne(text);
855
+ if (!date) return { error: `Enter a valid date (${resolvedFormat})` };
856
+ return { parts: [datePartsFromDate(date)] };
857
+ };
858
+ const isOutOfBounds = (parts) => parts.map(datePartsToDate).some((d) => d instanceof Date && !isWithinBounds(d));
859
+ const commitRawText = (text) => {
860
+ setEdit(null);
861
+ if (!text.trim()) {
862
+ setRawText(null);
863
+ setParseError(null);
864
+ setGroups(propGroups());
865
+ return;
866
+ }
867
+ const result = parseFieldText(text);
868
+ if ("error" in result) {
869
+ setParseError(result.error);
870
+ return;
871
+ }
872
+ if (isOutOfBounds(result.parts)) {
873
+ setParseError("Date must be within the allowed range");
874
+ return;
875
+ }
876
+ setRawText(null);
877
+ setParseError(null);
878
+ setGroups(result.parts);
879
+ emit(result.parts);
880
+ };
881
+ const handleChangeText = (text) => {
882
+ rest.onChangeText?.(text);
883
+ if (!editable) return;
884
+ markDirty();
885
+ setEdit(null);
886
+ setParseError(null);
887
+ setActiveSegment(null);
888
+ setRawText(text);
889
+ };
834
890
  const defaultPart = (type) => {
835
891
  const now = /* @__PURE__ */ new Date();
836
892
  if (type === "day") return now.getDate();
@@ -923,10 +979,12 @@ var DatePicker = forwardRef(
923
979
  }
924
980
  if (!isWeb || !editable) return;
925
981
  if (e.key === "Enter") {
926
- commitBuffer();
982
+ if (rawText !== null) commitRawText(rawText);
983
+ else commitBuffer();
927
984
  setOpen(false);
928
985
  return;
929
986
  }
987
+ if (rawText !== null && isSegmentKey(e.key)) setRawText(null);
930
988
  if (e.key === "ArrowUp") return handleArrowStep(e, 1);
931
989
  if (e.key === "ArrowDown") return handleArrowStep(e, -1);
932
990
  if (e.key === "ArrowLeft") return handleArrowMove(e, -1);
@@ -979,30 +1037,33 @@ var DatePicker = forwardRef(
979
1037
  setParseError(null);
980
1038
  return;
981
1039
  }
1040
+ if (rawText !== null) {
1041
+ commitRawText(rawText);
1042
+ return;
1043
+ }
982
1044
  let next = groups;
1045
+ let rejected = false;
983
1046
  if (edit) {
984
1047
  const clamped = clampDatePart(
985
1048
  edit.type,
986
1049
  Number(edit.buffer),
987
1050
  groups[edit.group]
988
1051
  );
989
- next = groups.map(
990
- (g, i) => i === edit.group ? { ...g, [edit.type]: clamped } : g
991
- );
1052
+ const edited = { ...groups[edit.group], [edit.type]: clamped };
1053
+ const assembled = datePartsToDate(edited);
1054
+ if (assembled && !isWithinBounds(assembled)) {
1055
+ rejected = true;
1056
+ } else {
1057
+ next = groups.map((g, i) => i === edit.group ? edited : g);
1058
+ }
992
1059
  }
993
1060
  const props = propGroups();
994
1061
  next = next.map((g, i) => isDatePartsComplete(g) ? g : props[i]);
995
1062
  setEdit(null);
996
- setParseError(null);
1063
+ setParseError(rejected ? "Date must be within the allowed range" : null);
997
1064
  setGroups(next);
998
1065
  emit(next);
999
1066
  };
1000
- const parseOne = (token) => {
1001
- const trimmed = token.trim();
1002
- if (!trimmed) return null;
1003
- const parsed = parse(trimmed, resolvedFormat, /* @__PURE__ */ new Date());
1004
- return isValid(parsed) ? parsed : null;
1005
- };
1006
1067
  const handlePaste = (e) => {
1007
1068
  onPasteProp?.(e);
1008
1069
  if (e.defaultPrevented) return;
@@ -1010,34 +1071,20 @@ var DatePicker = forwardRef(
1010
1071
  const text = e.clipboardData?.getData("text") ?? "";
1011
1072
  if (!text.trim()) return;
1012
1073
  e.preventDefault();
1013
- let next;
1014
- if (isRange) {
1015
- const [startText, endText] = text.split(RANGE_SEPARATOR);
1016
- const start = parseOne(startText ?? "");
1017
- const end = parseOne(endText ?? "");
1018
- if (!start) {
1019
- setParseError(
1020
- `Enter a valid date range (${resolvedFormat} - ${resolvedFormat})`
1021
- );
1022
- return;
1023
- }
1024
- next = [datePartsFromDate(start), datePartsFromDate(end)];
1025
- } else {
1026
- const date = parseOne(text);
1027
- if (!date) {
1028
- setParseError(`Enter a valid date (${resolvedFormat})`);
1029
- return;
1030
- }
1031
- next = [datePartsFromDate(date)];
1074
+ const result = parseFieldText(text);
1075
+ if ("error" in result) {
1076
+ setParseError(result.error);
1077
+ return;
1032
1078
  }
1033
- const outOfBounds = next.map(datePartsToDate).some((d) => d instanceof Date && !isWithinBounds(d));
1034
- if (outOfBounds) {
1079
+ const next = result.parts;
1080
+ if (isOutOfBounds(next)) {
1035
1081
  setParseError("Date must be within the allowed range");
1036
1082
  return;
1037
1083
  }
1038
1084
  markDirty();
1039
1085
  setParseError(null);
1040
1086
  setEdit(null);
1087
+ setRawText(null);
1041
1088
  setGroups(next);
1042
1089
  emit(next);
1043
1090
  };
@@ -1052,6 +1099,7 @@ var DatePicker = forwardRef(
1052
1099
  sessionRef.current.cleared = true;
1053
1100
  setGroups(next);
1054
1101
  setEdit(null);
1102
+ setRawText(null);
1055
1103
  setParseError(null);
1056
1104
  setInternalChip(null);
1057
1105
  onChipSelect?.(null);
@@ -1071,6 +1119,7 @@ var DatePicker = forwardRef(
1071
1119
  sessionRef.current = { dirty: false, cleared: false, propKey };
1072
1120
  setGroups(propGroups());
1073
1121
  setEdit(null);
1122
+ setRawText(null);
1074
1123
  setParseError(null);
1075
1124
  }, [propKey]);
1076
1125
  useEffect2(() => {
@@ -1268,6 +1317,7 @@ var DatePicker = forwardRef(
1268
1317
  onKeyDown: handleKeyDown,
1269
1318
  onClick: handleFieldClick,
1270
1319
  onPaste: handlePaste,
1320
+ onChangeText: handleChangeText,
1271
1321
  iconRight,
1272
1322
  iconLeft,
1273
1323
  extraClear: showClear,