@sustaina/shared-ui 1.70.6 → 1.70.8

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.js CHANGED
@@ -5543,6 +5543,77 @@ var DatePicker2 = (props) => {
5543
5543
  // src/components/advanceSearch/components/constants/index.ts
5544
5544
  var fallbackShortDateFormat = "DD/MM/YYYY";
5545
5545
  var UUIDregex = /^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$/i;
5546
+ var RANGE_START_ERROR = "Start value must be before end value.";
5547
+ var RANGE_END_ERROR = "End value must be after start value.";
5548
+ var RANGE_VALIDATED_TYPES = ["date", "datetime", "datemonth"];
5549
+ var sanitizeInput = (val) => {
5550
+ if (!val) return val;
5551
+ if (Array.isArray(val)) {
5552
+ return val.map((v) => sanitizeInput(v));
5553
+ }
5554
+ if (val.includes("\n") || val.includes("\r") || /[\u2028\u2029]/u.test(val))
5555
+ return "__INVALID_NEWLINE__";
5556
+ if (/\\\\/.test(val)) return "__INVALID_ESCAPE__";
5557
+ if (/\\(n|t|r|b|f|u[0-9a-fA-F]{4})/.test(val)) return "__INVALID_ESCAPE__";
5558
+ if (/\p{Cf}/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
5559
+ if (/[\u00A0\u1680\u180E\u202F\u205F\u3000]/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
5560
+ const trimmed = val.trim();
5561
+ if (/^\{.*\}$/s.test(trimmed) || /^\[.*\]$/s.test(trimmed)) return "__INVALID_JSON_LITERAL__";
5562
+ if (/\\\{/.test(val) || /\\\}/.test(val)) return "__INVALID_JSON_ESCAPE__";
5563
+ if (/[%*~^]/.test(trimmed)) return "__INVALID_WILDCARD__";
5564
+ if (/[%><={}\\[\]"']/u.test(trimmed)) return "__INVALID_CHAR__";
5565
+ if (/\p{Cc}/u.test(val)) return "__INVALID_CONTROL_CHAR__";
5566
+ return val;
5567
+ };
5568
+ var numericTypes = ["number"];
5569
+ var dateTypes = ["date", "datemonth"];
5570
+ var validateByFieldType = (value, fieldType) => {
5571
+ if (!value) return { valid: true };
5572
+ if (Array.isArray(value)) {
5573
+ return { valid: true };
5574
+ }
5575
+ if (numericTypes.includes(fieldType)) {
5576
+ if (!/^-?\d+(\.\d+)?$/.test(value)) {
5577
+ return { valid: false, message: "Please enter a valid number." };
5578
+ }
5579
+ }
5580
+ if (fieldType === "uuid") {
5581
+ if (!UUIDregex.test(value)) {
5582
+ return { valid: false, message: "Please enter a valid UUID." };
5583
+ }
5584
+ }
5585
+ if (dateTypes.includes(fieldType)) {
5586
+ const normalized = fieldType === "datemonth" ? `${value}-01` : value;
5587
+ const parsed = dateFns.parseISO(normalized);
5588
+ if (!dateFns.isValid(parsed)) {
5589
+ return { valid: false, message: "Invalid date format." };
5590
+ }
5591
+ }
5592
+ return { valid: true };
5593
+ };
5594
+ var parseRangeValue = (raw, fieldType) => {
5595
+ if (!raw) return void 0;
5596
+ const normalized = fieldType === "datemonth" ? `${raw}-01` : raw;
5597
+ const parsed = dateFns.parseISO(normalized);
5598
+ return dateFns.isValid(parsed) ? parsed : void 0;
5599
+ };
5600
+ var validateDateRange = (which, row, formValues) => {
5601
+ if (row.operator !== "between" || !RANGE_VALIDATED_TYPES.includes(row.fieldType)) return true;
5602
+ const start = formValues[`value_${row.id}`];
5603
+ const end = formValues[`value2_${row.id}`];
5604
+ if (typeof start !== "string" || typeof end !== "string" || !start || !end) return true;
5605
+ const d1 = parseRangeValue(start, row.fieldType);
5606
+ const d2 = parseRangeValue(end, row.fieldType);
5607
+ if (d1 && d2 && dateFns.isAfter(d1, d2)) {
5608
+ return which === "value" ? RANGE_START_ERROR : RANGE_END_ERROR;
5609
+ }
5610
+ return true;
5611
+ };
5612
+ var buildValueRules = (which, row) => ({
5613
+ required: "This field is required.",
5614
+ validate: (_value, formValues) => validateDateRange(which, row, formValues),
5615
+ deps: [which === "value" ? `value2_${row.id}` : `value_${row.id}`]
5616
+ });
5546
5617
  var ConditionDateInput = ({
5547
5618
  row,
5548
5619
  control,
@@ -5566,8 +5637,9 @@ var ConditionDateInput = ({
5566
5637
  {
5567
5638
  control,
5568
5639
  name: fieldName,
5569
- rules: { required: "This field is required." },
5640
+ rules: buildValueRules(which, row),
5570
5641
  render: ({ field, fieldState }) => {
5642
+ const { value: fieldValue, ...fieldRest } = field;
5571
5643
  const handleValueChange = (next) => {
5572
5644
  field.onChange(next ?? void 0);
5573
5645
  if (!next) {
@@ -5578,8 +5650,8 @@ var ConditionDateInput = ({
5578
5650
  /* @__PURE__ */ jsxRuntime.jsx(FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
5579
5651
  DatePicker2,
5580
5652
  {
5581
- ...field,
5582
- value: field.value || void 0,
5653
+ ...fieldRest,
5654
+ value: fieldValue || void 0,
5583
5655
  onValueChange: handleValueChange,
5584
5656
  placeholder: dateFormat,
5585
5657
  ariaLabel: buildAriaLabel(options?.isEnd),
@@ -5699,12 +5771,9 @@ function MonthCal({
5699
5771
  );
5700
5772
  const min = React__namespace.useMemo(() => normalizeMonth(minDate), [minDate]);
5701
5773
  const max = React__namespace.useMemo(() => normalizeMonth(maxDate), [maxDate]);
5702
- let effectiveMin = min;
5703
- if (min && max && min > max) {
5704
- effectiveMin = max;
5705
- }
5706
- const minYear = effectiveMin?.getFullYear();
5707
- const minMonth = effectiveMin?.getMonth();
5774
+ const hasConflictingBounds = Boolean(min && max && min > max);
5775
+ const minYear = min?.getFullYear();
5776
+ const minMonth = min?.getMonth();
5708
5777
  const maxYear = max?.getFullYear();
5709
5778
  const maxMonth = max?.getMonth();
5710
5779
  const selectedMonthYear = selectedMonthDate?.getFullYear();
@@ -5717,6 +5786,7 @@ function MonthCal({
5717
5786
  }
5718
5787
  }, [selectedMonthYear]);
5719
5788
  React__namespace.useEffect(() => {
5789
+ if (hasConflictingBounds) return;
5720
5790
  if (typeof minYear === "number" && menuYear < minYear) {
5721
5791
  setMenuYear(minYear);
5722
5792
  return;
@@ -5724,10 +5794,11 @@ function MonthCal({
5724
5794
  if (typeof maxYear === "number" && menuYear > maxYear) {
5725
5795
  setMenuYear(maxYear);
5726
5796
  }
5727
- }, [minYear, maxYear, menuYear]);
5728
- const disablePrevYear = typeof minYear === "number" ? menuYear <= minYear : false;
5729
- const disableNextYear = typeof maxYear === "number" ? menuYear >= maxYear : false;
5797
+ }, [hasConflictingBounds, minYear, maxYear, menuYear]);
5798
+ const disablePrevYear = hasConflictingBounds || (typeof minYear === "number" ? menuYear <= minYear : false);
5799
+ const disableNextYear = hasConflictingBounds || (typeof maxYear === "number" ? menuYear >= maxYear : false);
5730
5800
  const yearOptions = React__namespace.useMemo(() => {
5801
+ if (hasConflictingBounds) return [menuYear];
5731
5802
  const fallbackWindow = 50;
5732
5803
  const start = typeof minYear === "number" ? minYear : menuYear - fallbackWindow;
5733
5804
  const end = typeof maxYear === "number" ? maxYear : menuYear + fallbackWindow;
@@ -5740,7 +5811,7 @@ function MonthCal({
5740
5811
  years.sort((a, b) => a - b);
5741
5812
  }
5742
5813
  return years;
5743
- }, [maxYear, menuYear, minYear]);
5814
+ }, [hasConflictingBounds, maxYear, menuYear, minYear]);
5744
5815
  const formatYearLabel = React__namespace.useCallback(
5745
5816
  (year) => {
5746
5817
  const raw = callbacks?.yearLabel?.(year);
@@ -5751,13 +5822,14 @@ function MonthCal({
5751
5822
  );
5752
5823
  const handleYearSelect = React__namespace.useCallback(
5753
5824
  (nextValue) => {
5825
+ if (hasConflictingBounds) return;
5754
5826
  const nextYear = Number.parseInt(nextValue, 10);
5755
5827
  if (Number.isNaN(nextYear)) return;
5756
5828
  if (typeof minYear === "number" && nextYear < minYear) return;
5757
5829
  if (typeof maxYear === "number" && nextYear > maxYear) return;
5758
5830
  setMenuYear(nextYear);
5759
5831
  },
5760
- [maxYear, minYear]
5832
+ [hasConflictingBounds, maxYear, minYear]
5761
5833
  );
5762
5834
  const disabledPairs = React__namespace.useMemo(() => {
5763
5835
  if (!disabledDates?.length) return [];
@@ -5842,7 +5914,7 @@ function MonthCal({
5842
5914
  const disabledByList = disabledPairs.some(
5843
5915
  (d) => d.year === menuYear && d.month === m.number
5844
5916
  );
5845
- const isDisabled = afterMax || beforeMin || disabledByList;
5917
+ const isDisabled = hasConflictingBounds || afterMax || beforeMin || disabledByList;
5846
5918
  const cellDate = new Date(menuYear, m.number, 1);
5847
5919
  cellDate.setHours(0, 0, 0, 0);
5848
5920
  const isSelected = !isDisabled && !!selectedMonthDate && selectedMonthDate.getFullYear() === menuYear && selectedMonthDate.getMonth() === m.number;
@@ -6088,9 +6160,10 @@ var ConditionMonthInput = ({ row, control, onClear }) => {
6088
6160
  {
6089
6161
  control,
6090
6162
  name: fieldName,
6091
- rules: { required: "This field is required." },
6163
+ rules: buildValueRules(which, row),
6092
6164
  render: ({ field, fieldState }) => {
6093
- const value = field.value || void 0;
6165
+ const { value: fieldValue, ...fieldRest } = field;
6166
+ const value = fieldValue || void 0;
6094
6167
  const handleValueChange = (next) => {
6095
6168
  field.onChange(next ?? void 0);
6096
6169
  if (!next) {
@@ -6101,7 +6174,7 @@ var ConditionMonthInput = ({ row, control, onClear }) => {
6101
6174
  /* @__PURE__ */ jsxRuntime.jsx(FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
6102
6175
  MonthPicker2,
6103
6176
  {
6104
- ...field,
6177
+ ...fieldRest,
6105
6178
  value,
6106
6179
  onValueChange: handleValueChange,
6107
6180
  placeholder,
@@ -8648,51 +8721,6 @@ function transformFilterKeys(obj, fieldMap = FILTER_FIELD_MAP) {
8648
8721
  }
8649
8722
  return obj;
8650
8723
  }
8651
- var sanitizeInput = (val) => {
8652
- if (!val) return val;
8653
- if (Array.isArray(val)) {
8654
- return val.map((v) => sanitizeInput(v));
8655
- }
8656
- if (val.includes("\n") || val.includes("\r") || /[\u2028\u2029]/u.test(val))
8657
- return "__INVALID_NEWLINE__";
8658
- if (/\\\\/.test(val)) return "__INVALID_ESCAPE__";
8659
- if (/\\(n|t|r|b|f|u[0-9a-fA-F]{4})/.test(val)) return "__INVALID_ESCAPE__";
8660
- if (/\p{Cf}/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
8661
- if (/[\u00A0\u1680\u180E\u202F\u205F\u3000]/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
8662
- const trimmed = val.trim();
8663
- if (/^\{.*\}$/s.test(trimmed) || /^\[.*\]$/s.test(trimmed)) return "__INVALID_JSON_LITERAL__";
8664
- if (/\\\{/.test(val) || /\\\}/.test(val)) return "__INVALID_JSON_ESCAPE__";
8665
- if (/[%*~^]/.test(trimmed)) return "__INVALID_WILDCARD__";
8666
- if (/[%><={}\\[\]"']/u.test(trimmed)) return "__INVALID_CHAR__";
8667
- if (/\p{Cc}/u.test(val)) return "__INVALID_CONTROL_CHAR__";
8668
- return val;
8669
- };
8670
- var numericTypes = ["number"];
8671
- var dateTypes = ["date", "datemonth"];
8672
- var validateByFieldType = (value, fieldType) => {
8673
- if (!value) return { valid: true };
8674
- if (Array.isArray(value)) {
8675
- return { valid: true };
8676
- }
8677
- if (numericTypes.includes(fieldType)) {
8678
- if (!/^-?\d+(\.\d+)?$/.test(value)) {
8679
- return { valid: false, message: "Please enter a valid number." };
8680
- }
8681
- }
8682
- if (fieldType === "uuid") {
8683
- if (!UUIDregex.test(value)) {
8684
- return { valid: false, message: "Please enter a valid UUID." };
8685
- }
8686
- }
8687
- if (dateTypes.includes(fieldType)) {
8688
- const normalized = fieldType === "datemonth" ? `${value}-01` : value;
8689
- const parsed = dateFns.parseISO(normalized);
8690
- if (!dateFns.isValid(parsed)) {
8691
- return { valid: false, message: "Invalid date format." };
8692
- }
8693
- }
8694
- return { valid: true };
8695
- };
8696
8724
  var AdvanceSearch = ({
8697
8725
  fields,
8698
8726
  portalId,
@@ -8720,7 +8748,7 @@ var AdvanceSearch = ({
8720
8748
  } = useAdvanceSearch({ fields: fieldsData, limitRows });
8721
8749
  const form = reactHookForm.useForm({
8722
8750
  mode: "onSubmit",
8723
- reValidateMode: "onSubmit",
8751
+ reValidateMode: "onChange",
8724
8752
  defaultValues: {}
8725
8753
  });
8726
8754
  const { handleSubmit, unregister, resetField, getValues, clearErrors, setError } = form;
@@ -8745,13 +8773,6 @@ var AdvanceSearch = ({
8745
8773
  },
8746
8774
  [resetField, clearErrors]
8747
8775
  );
8748
- const parseRangeValue = React.useCallback((raw, fieldType) => {
8749
- if (!raw) return void 0;
8750
- if (Array.isArray(raw)) return void 0;
8751
- const normalized = fieldType === "datemonth" ? `${raw}-01` : raw;
8752
- const parsed = dateFns.parseISO(normalized);
8753
- return dateFns.isValid(parsed) ? parsed : void 0;
8754
- }, []);
8755
8776
  const onSubmit = React.useCallback(() => {
8756
8777
  const operatorValidation = {};
8757
8778
  rows.forEach((r) => {
@@ -8795,16 +8816,6 @@ var AdvanceSearch = ({
8795
8816
  setError(endField, { type: "validate", message: valid2.message });
8796
8817
  return null;
8797
8818
  }
8798
- if (v1 && v2 && ["date", "datemonth"].includes(r.fieldType)) {
8799
- const d1 = parseRangeValue(v1, r.fieldType);
8800
- const d2 = parseRangeValue(v2, r.fieldType);
8801
- if (d1 && d2 && dateFns.isAfter(d1, d2)) {
8802
- hasError = true;
8803
- setError(startField, { type: "validate", message: "Start value must be before end value." });
8804
- setError(endField, { type: "validate", message: "End value must be after start value." });
8805
- return null;
8806
- }
8807
- }
8808
8819
  return { ...r, value: v1, value2: v2 };
8809
8820
  }
8810
8821
  return { ...r, value: v1 };
@@ -8834,7 +8845,6 @@ var AdvanceSearch = ({
8834
8845
  rows,
8835
8846
  operatorsForField,
8836
8847
  getValues,
8837
- parseRangeValue,
8838
8848
  setError,
8839
8849
  setOperatorErrors,
8840
8850
  filterFieldMap,
@@ -13874,8 +13884,8 @@ var GridSettingsModal = ({
13874
13884
  }
13875
13885
  }, [isOpen, currentColumns, form]);
13876
13886
  const addColumn = async () => {
13877
- const isValid7 = await trigger("columns");
13878
- if (isValid7) {
13887
+ const isValid6 = await trigger("columns");
13888
+ if (isValid6) {
13879
13889
  append({ id: "" });
13880
13890
  requestAnimationFrame(() => {
13881
13891
  const container = scrollRef.current;