@sustaina/shared-ui 1.70.7 → 1.71.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.mjs CHANGED
@@ -15,7 +15,7 @@ import { createPortal } from 'react-dom';
15
15
  import * as SelectPrimitive from '@radix-ui/react-select';
16
16
  import { useForm, FormProvider, Controller, useFormContext, useFormState, useFieldArray, useWatch } from 'react-hook-form';
17
17
  import * as LabelPrimitive from '@radix-ui/react-label';
18
- import { format, isValid, parseISO, isAfter, compareAsc, parse } from 'date-fns';
18
+ import { format, isValid, parseISO, compareAsc, parse, isAfter } from 'date-fns';
19
19
  import * as PopoverPrimitive from '@radix-ui/react-popover';
20
20
  import { Command as Command$1 } from 'cmdk';
21
21
  import * as DialogPrimitive2 from '@radix-ui/react-dialog';
@@ -5500,6 +5500,78 @@ var DatePicker2 = (props) => {
5500
5500
  // src/components/advanceSearch/components/constants/index.ts
5501
5501
  var fallbackShortDateFormat = "DD/MM/YYYY";
5502
5502
  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;
5503
+ var RANGE_START_ERROR = "Start value must be before end value.";
5504
+ var RANGE_END_ERROR = "End value must be after start value.";
5505
+ var RANGE_VALIDATED_TYPES = ["date", "datetime", "datemonth"];
5506
+ var sanitizeInput = (val, fieldType) => {
5507
+ if (!val) return val;
5508
+ if (Array.isArray(val)) {
5509
+ return val.map((v) => sanitizeInput(v, fieldType));
5510
+ }
5511
+ if (val.includes("\n") || val.includes("\r") || /[\u2028\u2029]/u.test(val))
5512
+ return "__INVALID_NEWLINE__";
5513
+ if (/\\\\/.test(val)) return "__INVALID_ESCAPE__";
5514
+ if (/\\(n|t|r|b|f|u[0-9a-fA-F]{4})/.test(val)) return "__INVALID_ESCAPE__";
5515
+ if (/\p{Cf}/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
5516
+ if (/[\u00A0\u1680\u180E\u202F\u205F\u3000]/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
5517
+ if (fieldType === "text") return val;
5518
+ const trimmed = val.trim();
5519
+ if (/^\{.*\}$/s.test(trimmed) || /^\[.*\]$/s.test(trimmed)) return "__INVALID_JSON_LITERAL__";
5520
+ if (/\\\{/.test(val) || /\\\}/.test(val)) return "__INVALID_JSON_ESCAPE__";
5521
+ if (/[%*~^]/.test(trimmed)) return "__INVALID_WILDCARD__";
5522
+ if (/[%><={}\\[\]"']/u.test(trimmed)) return "__INVALID_CHAR__";
5523
+ if (/\p{Cc}/u.test(val)) return "__INVALID_CONTROL_CHAR__";
5524
+ return val;
5525
+ };
5526
+ var numericTypes = ["number"];
5527
+ var dateTypes = ["date", "datemonth"];
5528
+ var validateByFieldType = (value, fieldType) => {
5529
+ if (!value) return { valid: true };
5530
+ if (Array.isArray(value)) {
5531
+ return { valid: true };
5532
+ }
5533
+ if (numericTypes.includes(fieldType)) {
5534
+ if (!/^-?\d+(\.\d+)?$/.test(value)) {
5535
+ return { valid: false, message: "Please enter a valid number." };
5536
+ }
5537
+ }
5538
+ if (fieldType === "uuid") {
5539
+ if (!UUIDregex.test(value)) {
5540
+ return { valid: false, message: "Please enter a valid UUID." };
5541
+ }
5542
+ }
5543
+ if (dateTypes.includes(fieldType)) {
5544
+ const normalized = fieldType === "datemonth" ? `${value}-01` : value;
5545
+ const parsed = parseISO(normalized);
5546
+ if (!isValid(parsed)) {
5547
+ return { valid: false, message: "Invalid date format." };
5548
+ }
5549
+ }
5550
+ return { valid: true };
5551
+ };
5552
+ var parseRangeValue = (raw, fieldType) => {
5553
+ if (!raw) return void 0;
5554
+ const normalized = fieldType === "datemonth" ? `${raw}-01` : raw;
5555
+ const parsed = parseISO(normalized);
5556
+ return isValid(parsed) ? parsed : void 0;
5557
+ };
5558
+ var validateDateRange = (which, row, formValues) => {
5559
+ if (row.operator !== "between" || !RANGE_VALIDATED_TYPES.includes(row.fieldType)) return true;
5560
+ const start = formValues[`value_${row.id}`];
5561
+ const end = formValues[`value2_${row.id}`];
5562
+ if (typeof start !== "string" || typeof end !== "string" || !start || !end) return true;
5563
+ const d1 = parseRangeValue(start, row.fieldType);
5564
+ const d2 = parseRangeValue(end, row.fieldType);
5565
+ if (d1 && d2 && isAfter(d1, d2)) {
5566
+ return which === "value" ? RANGE_START_ERROR : RANGE_END_ERROR;
5567
+ }
5568
+ return true;
5569
+ };
5570
+ var buildValueRules = (which, row) => ({
5571
+ required: "This field is required.",
5572
+ validate: (_value, formValues) => validateDateRange(which, row, formValues),
5573
+ deps: [which === "value" ? `value2_${row.id}` : `value_${row.id}`]
5574
+ });
5503
5575
  var ConditionDateInput = ({
5504
5576
  row,
5505
5577
  control,
@@ -5523,8 +5595,9 @@ var ConditionDateInput = ({
5523
5595
  {
5524
5596
  control,
5525
5597
  name: fieldName,
5526
- rules: { required: "This field is required." },
5598
+ rules: buildValueRules(which, row),
5527
5599
  render: ({ field, fieldState }) => {
5600
+ const { value: fieldValue, ...fieldRest } = field;
5528
5601
  const handleValueChange = (next) => {
5529
5602
  field.onChange(next ?? void 0);
5530
5603
  if (!next) {
@@ -5535,8 +5608,8 @@ var ConditionDateInput = ({
5535
5608
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
5536
5609
  DatePicker2,
5537
5610
  {
5538
- ...field,
5539
- value: field.value || void 0,
5611
+ ...fieldRest,
5612
+ value: fieldValue || void 0,
5540
5613
  onValueChange: handleValueChange,
5541
5614
  placeholder: dateFormat,
5542
5615
  ariaLabel: buildAriaLabel(options?.isEnd),
@@ -6045,9 +6118,10 @@ var ConditionMonthInput = ({ row, control, onClear }) => {
6045
6118
  {
6046
6119
  control,
6047
6120
  name: fieldName,
6048
- rules: { required: "This field is required." },
6121
+ rules: buildValueRules(which, row),
6049
6122
  render: ({ field, fieldState }) => {
6050
- const value = field.value || void 0;
6123
+ const { value: fieldValue, ...fieldRest } = field;
6124
+ const value = fieldValue || void 0;
6051
6125
  const handleValueChange = (next) => {
6052
6126
  field.onChange(next ?? void 0);
6053
6127
  if (!next) {
@@ -6058,7 +6132,7 @@ var ConditionMonthInput = ({ row, control, onClear }) => {
6058
6132
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
6059
6133
  MonthPicker2,
6060
6134
  {
6061
- ...field,
6135
+ ...fieldRest,
6062
6136
  value,
6063
6137
  onValueChange: handleValueChange,
6064
6138
  placeholder,
@@ -8605,51 +8679,6 @@ function transformFilterKeys(obj, fieldMap = FILTER_FIELD_MAP) {
8605
8679
  }
8606
8680
  return obj;
8607
8681
  }
8608
- var sanitizeInput = (val) => {
8609
- if (!val) return val;
8610
- if (Array.isArray(val)) {
8611
- return val.map((v) => sanitizeInput(v));
8612
- }
8613
- if (val.includes("\n") || val.includes("\r") || /[\u2028\u2029]/u.test(val))
8614
- return "__INVALID_NEWLINE__";
8615
- if (/\\\\/.test(val)) return "__INVALID_ESCAPE__";
8616
- if (/\\(n|t|r|b|f|u[0-9a-fA-F]{4})/.test(val)) return "__INVALID_ESCAPE__";
8617
- if (/\p{Cf}/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
8618
- if (/[\u00A0\u1680\u180E\u202F\u205F\u3000]/u.test(val)) return "__INVALID_UNICODE_WHITESPACE__";
8619
- const trimmed = val.trim();
8620
- if (/^\{.*\}$/s.test(trimmed) || /^\[.*\]$/s.test(trimmed)) return "__INVALID_JSON_LITERAL__";
8621
- if (/\\\{/.test(val) || /\\\}/.test(val)) return "__INVALID_JSON_ESCAPE__";
8622
- if (/[%*~^]/.test(trimmed)) return "__INVALID_WILDCARD__";
8623
- if (/[%><={}\\[\]"']/u.test(trimmed)) return "__INVALID_CHAR__";
8624
- if (/\p{Cc}/u.test(val)) return "__INVALID_CONTROL_CHAR__";
8625
- return val;
8626
- };
8627
- var numericTypes = ["number"];
8628
- var dateTypes = ["date", "datemonth"];
8629
- var validateByFieldType = (value, fieldType) => {
8630
- if (!value) return { valid: true };
8631
- if (Array.isArray(value)) {
8632
- return { valid: true };
8633
- }
8634
- if (numericTypes.includes(fieldType)) {
8635
- if (!/^-?\d+(\.\d+)?$/.test(value)) {
8636
- return { valid: false, message: "Please enter a valid number." };
8637
- }
8638
- }
8639
- if (fieldType === "uuid") {
8640
- if (!UUIDregex.test(value)) {
8641
- return { valid: false, message: "Please enter a valid UUID." };
8642
- }
8643
- }
8644
- if (dateTypes.includes(fieldType)) {
8645
- const normalized = fieldType === "datemonth" ? `${value}-01` : value;
8646
- const parsed = parseISO(normalized);
8647
- if (!isValid(parsed)) {
8648
- return { valid: false, message: "Invalid date format." };
8649
- }
8650
- }
8651
- return { valid: true };
8652
- };
8653
8682
  var AdvanceSearch = ({
8654
8683
  fields,
8655
8684
  portalId,
@@ -8702,13 +8731,6 @@ var AdvanceSearch = ({
8702
8731
  },
8703
8732
  [resetField, clearErrors]
8704
8733
  );
8705
- const parseRangeValue = useCallback((raw, fieldType) => {
8706
- if (!raw) return void 0;
8707
- if (Array.isArray(raw)) return void 0;
8708
- const normalized = fieldType === "datemonth" ? `${raw}-01` : raw;
8709
- const parsed = parseISO(normalized);
8710
- return isValid(parsed) ? parsed : void 0;
8711
- }, []);
8712
8734
  const onSubmit = useCallback(() => {
8713
8735
  const operatorValidation = {};
8714
8736
  rows.forEach((r) => {
@@ -8725,7 +8747,7 @@ var AdvanceSearch = ({
8725
8747
  const endField = `value2_${r.id}`;
8726
8748
  let v1 = currentValues[startField];
8727
8749
  let v2 = currentValues[endField];
8728
- const s1 = sanitizeInput(v1);
8750
+ const s1 = sanitizeInput(v1, r.fieldType);
8729
8751
  if (Array.isArray(s1) && s1.some((v) => v?.startsWith("__INVALID")) || typeof s1 === "string" && s1?.startsWith("__INVALID")) {
8730
8752
  hasError = true;
8731
8753
  setError(startField, { type: "validate", message: "Invalid input." });
@@ -8739,7 +8761,7 @@ var AdvanceSearch = ({
8739
8761
  return null;
8740
8762
  }
8741
8763
  if (r.operator === "between") {
8742
- const s2 = sanitizeInput(v2);
8764
+ const s2 = sanitizeInput(v2, r.fieldType);
8743
8765
  if (Array.isArray(s2) && s2.some((v) => v?.startsWith("__INVALID")) || typeof s2 === "string" && s2?.startsWith("__INVALID")) {
8744
8766
  hasError = true;
8745
8767
  setError(endField, { type: "validate", message: "Invalid input." });
@@ -8752,16 +8774,6 @@ var AdvanceSearch = ({
8752
8774
  setError(endField, { type: "validate", message: valid2.message });
8753
8775
  return null;
8754
8776
  }
8755
- if (v1 && v2 && ["date", "datemonth"].includes(r.fieldType)) {
8756
- const d1 = parseRangeValue(v1, r.fieldType);
8757
- const d2 = parseRangeValue(v2, r.fieldType);
8758
- if (d1 && d2 && isAfter(d1, d2)) {
8759
- hasError = true;
8760
- setError(startField, { type: "validate", message: "Start value must be before end value." });
8761
- setError(endField, { type: "validate", message: "End value must be after start value." });
8762
- return null;
8763
- }
8764
- }
8765
8777
  return { ...r, value: v1, value2: v2 };
8766
8778
  }
8767
8779
  return { ...r, value: v1 };
@@ -8791,7 +8803,6 @@ var AdvanceSearch = ({
8791
8803
  rows,
8792
8804
  operatorsForField,
8793
8805
  getValues,
8794
- parseRangeValue,
8795
8806
  setError,
8796
8807
  setOperatorErrors,
8797
8808
  filterFieldMap,
@@ -13831,8 +13842,8 @@ var GridSettingsModal = ({
13831
13842
  }
13832
13843
  }, [isOpen, currentColumns, form]);
13833
13844
  const addColumn = async () => {
13834
- const isValid7 = await trigger("columns");
13835
- if (isValid7) {
13845
+ const isValid6 = await trigger("columns");
13846
+ if (isValid6) {
13836
13847
  append({ id: "" });
13837
13848
  requestAnimationFrame(() => {
13838
13849
  const container = scrollRef.current;