@openg2p/registry-widgets 1.1.0-dev.14 → 1.1.0-dev.15
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/components/SectionBuilder/schemas.d.ts +48 -0
- package/dist/components/SectionBuilder/schemas.d.ts.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.esm.js +203 -63
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +203 -63
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/dateInput.d.ts +17 -1
- package/dist/utils/dateInput.d.ts.map +1 -1
- package/dist/widgets/DateInputWidget.d.ts +5 -0
- package/dist/widgets/DateInputWidget.d.ts.map +1 -1
- package/dist/widgets/TableWidget.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -371,6 +371,18 @@ export declare const panelSchema: {
|
|
|
371
371
|
maxDate: {
|
|
372
372
|
type: "string";
|
|
373
373
|
};
|
|
374
|
+
minDateField: {
|
|
375
|
+
type: "string";
|
|
376
|
+
};
|
|
377
|
+
maxDateField: {
|
|
378
|
+
type: "string";
|
|
379
|
+
};
|
|
380
|
+
minDateMessage: {
|
|
381
|
+
type: "string";
|
|
382
|
+
};
|
|
383
|
+
maxDateMessage: {
|
|
384
|
+
type: "string";
|
|
385
|
+
};
|
|
374
386
|
showCalendar: {
|
|
375
387
|
type: "boolean";
|
|
376
388
|
};
|
|
@@ -835,6 +847,18 @@ export declare const panelSchema: {
|
|
|
835
847
|
maxDate: {
|
|
836
848
|
type: "string";
|
|
837
849
|
};
|
|
850
|
+
minDateField: {
|
|
851
|
+
type: "string";
|
|
852
|
+
};
|
|
853
|
+
maxDateField: {
|
|
854
|
+
type: "string";
|
|
855
|
+
};
|
|
856
|
+
minDateMessage: {
|
|
857
|
+
type: "string";
|
|
858
|
+
};
|
|
859
|
+
maxDateMessage: {
|
|
860
|
+
type: "string";
|
|
861
|
+
};
|
|
838
862
|
showCalendar: {
|
|
839
863
|
type: "boolean";
|
|
840
864
|
};
|
|
@@ -1362,6 +1386,18 @@ export declare const sectionSchema: {
|
|
|
1362
1386
|
maxDate: {
|
|
1363
1387
|
type: "string";
|
|
1364
1388
|
};
|
|
1389
|
+
minDateField: {
|
|
1390
|
+
type: "string";
|
|
1391
|
+
};
|
|
1392
|
+
maxDateField: {
|
|
1393
|
+
type: "string";
|
|
1394
|
+
};
|
|
1395
|
+
minDateMessage: {
|
|
1396
|
+
type: "string";
|
|
1397
|
+
};
|
|
1398
|
+
maxDateMessage: {
|
|
1399
|
+
type: "string";
|
|
1400
|
+
};
|
|
1365
1401
|
showCalendar: {
|
|
1366
1402
|
type: "boolean";
|
|
1367
1403
|
};
|
|
@@ -1826,6 +1862,18 @@ export declare const sectionSchema: {
|
|
|
1826
1862
|
maxDate: {
|
|
1827
1863
|
type: "string";
|
|
1828
1864
|
};
|
|
1865
|
+
minDateField: {
|
|
1866
|
+
type: "string";
|
|
1867
|
+
};
|
|
1868
|
+
maxDateField: {
|
|
1869
|
+
type: "string";
|
|
1870
|
+
};
|
|
1871
|
+
minDateMessage: {
|
|
1872
|
+
type: "string";
|
|
1873
|
+
};
|
|
1874
|
+
maxDateMessage: {
|
|
1875
|
+
type: "string";
|
|
1876
|
+
};
|
|
1829
1877
|
showCalendar: {
|
|
1830
1878
|
type: "boolean";
|
|
1831
1879
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/components/SectionBuilder/schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,YAAY,yNAmBf,CAAC;AAEX,eAAO,MAAM,YAAY,qCAAsC,CAAC;AAEhE,eAAO,MAAM,mBAAmB,6GAStB,CAAC;AAEX,eAAO,MAAM,iBAAiB,sCAAuC,CAAC;AAEtE,eAAO,MAAM,gBAAgB,oCAAqC,CAAC;AAEnE,eAAO,MAAM,eAAe,wFAOlB,CAAC;AAEX,eAAO,MAAM,aAAa,2DAA4D,CAAC;AAEvF,eAAO,MAAM,aAAa,iCAAkC,CAAC;AAE7D,eAAO,MAAM,uBAAuB,uDAAwD,CAAC;AAE7F,eAAO,MAAM,qBAAqB,0CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/components/SectionBuilder/schemas.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -175,6 +175,10 @@ interface WidgetOptions {
|
|
|
175
175
|
condition?: WidgetCondition;
|
|
176
176
|
minDate?: string;
|
|
177
177
|
maxDate?: string;
|
|
178
|
+
minDateField?: string;
|
|
179
|
+
maxDateField?: string;
|
|
180
|
+
minDateMessage?: string;
|
|
181
|
+
maxDateMessage?: string;
|
|
178
182
|
showCalendar?: boolean;
|
|
179
183
|
[key: string]: any;
|
|
180
184
|
}
|
|
@@ -978,6 +982,7 @@ declare const BooleanWidget: ({ config }: BooleanWidgetProps) => react_jsx_runti
|
|
|
978
982
|
* - Configurable date format (DD/MM/YYYY, MM/DD/YYYY, YYYY-MM-DD, etc.)
|
|
979
983
|
* - Default value (none / today)
|
|
980
984
|
* - Date constraints (minDate, maxDate, any/past only/future only)
|
|
985
|
+
* - Relative bounds via minDateField / maxDateField (e.g. end date >= start date)
|
|
981
986
|
* - Required vs optional
|
|
982
987
|
* - Input method (date picker / manual / hybrid)
|
|
983
988
|
* - Placeholder text
|
|
@@ -1000,6 +1005,10 @@ declare const BooleanWidget: ({ config }: BooleanWidgetProps) => react_jsx_runti
|
|
|
1000
1005
|
* "widget-data-options": {
|
|
1001
1006
|
* "minDate": "1900-01-01",
|
|
1002
1007
|
* "maxDate": "today"
|
|
1008
|
+
* "minDateField": "register.start_date",
|
|
1009
|
+
* "minDateMessage": "Date of birth must be on or after 1900-01-01"
|
|
1010
|
+
* "maxDateField": "register.end_date",
|
|
1011
|
+
* "maxDateMessage": "Date of birth must be on or before today"
|
|
1003
1012
|
* },
|
|
1004
1013
|
* "widget-data-validation": {},
|
|
1005
1014
|
* "widget-required": true,
|
package/dist/index.esm.js
CHANGED
|
@@ -807,6 +807,40 @@ const parseDateFromFormat = (dateString, format) => {
|
|
|
807
807
|
}
|
|
808
808
|
return parseDate(dateString);
|
|
809
809
|
};
|
|
810
|
+
/**
|
|
811
|
+
* Resolve a stored date value (ISO or parseable string) to YYYY-MM-DD for comparisons.
|
|
812
|
+
*/
|
|
813
|
+
const resolveDateBoundFromFieldValue = (fieldValue) => {
|
|
814
|
+
if (fieldValue == null || fieldValue === '') {
|
|
815
|
+
return undefined;
|
|
816
|
+
}
|
|
817
|
+
const iso = formatDateToISO(fieldValue);
|
|
818
|
+
return iso || undefined;
|
|
819
|
+
};
|
|
820
|
+
/**
|
|
821
|
+
* Pick the stricter (later) minimum when combining static and field-based bounds.
|
|
822
|
+
*/
|
|
823
|
+
const mergeMinDateBounds = (boundA, boundB) => {
|
|
824
|
+
if (!boundA) {
|
|
825
|
+
return boundB;
|
|
826
|
+
}
|
|
827
|
+
if (!boundB) {
|
|
828
|
+
return boundA;
|
|
829
|
+
}
|
|
830
|
+
return boundA > boundB ? boundA : boundB;
|
|
831
|
+
};
|
|
832
|
+
/**
|
|
833
|
+
* Pick the stricter (earlier) maximum when combining static and field-based bounds.
|
|
834
|
+
*/
|
|
835
|
+
const mergeMaxDateBounds = (boundA, boundB) => {
|
|
836
|
+
if (!boundA) {
|
|
837
|
+
return boundB;
|
|
838
|
+
}
|
|
839
|
+
if (!boundB) {
|
|
840
|
+
return boundA;
|
|
841
|
+
}
|
|
842
|
+
return boundA < boundB ? boundA : boundB;
|
|
843
|
+
};
|
|
810
844
|
/**
|
|
811
845
|
* Get min date based on constraint type
|
|
812
846
|
*/
|
|
@@ -849,10 +883,7 @@ const getMaxDate = (constraint, maxDate) => {
|
|
|
849
883
|
}
|
|
850
884
|
return undefined;
|
|
851
885
|
};
|
|
852
|
-
|
|
853
|
-
* Validate date constraints
|
|
854
|
-
*/
|
|
855
|
-
const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
886
|
+
const validateDateConstraints = (date, minDate, maxDate, constraint, messages) => {
|
|
856
887
|
if (!date)
|
|
857
888
|
return null;
|
|
858
889
|
const dateObj = date instanceof Date ? date : parseDate(date);
|
|
@@ -871,15 +902,12 @@ const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
|
871
902
|
return 'Date must be in the future';
|
|
872
903
|
}
|
|
873
904
|
}
|
|
874
|
-
//
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
return `Date must be on or after ${effectiveMinDate}`;
|
|
905
|
+
// minDate / maxDate are effective bounds (static + field-based), resolved by the caller
|
|
906
|
+
if (minDate && dateISO < minDate) {
|
|
907
|
+
return messages?.minDateMessage ?? `Date must be on or after ${minDate}`;
|
|
878
908
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
if (effectiveMaxDate && dateISO > effectiveMaxDate) {
|
|
882
|
-
return `Date must be on or before ${effectiveMaxDate}`;
|
|
909
|
+
if (maxDate && dateISO > maxDate) {
|
|
910
|
+
return messages?.maxDateMessage ?? `Date must be on or before ${maxDate}`;
|
|
883
911
|
}
|
|
884
912
|
return null;
|
|
885
913
|
};
|
|
@@ -7647,42 +7675,76 @@ const BooleanWidget = ({ config }) => {
|
|
|
7647
7675
|
};
|
|
7648
7676
|
|
|
7649
7677
|
const DateInputWidget = ({ config }) => {
|
|
7650
|
-
const { value,
|
|
7651
|
-
const
|
|
7678
|
+
const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
|
|
7679
|
+
const formValues = useSelector((state) => state.widget.values);
|
|
7680
|
+
const { translateConfig } = useWidgetTranslation();
|
|
7652
7681
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7653
7682
|
const optionsConfig = widgetConfig['widget-data-options'];
|
|
7654
7683
|
const dateFormat = formatConfig?.dateFormat || 'YYYY-MM-DD';
|
|
7655
|
-
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7684
|
+
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7656
7685
|
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
7657
7686
|
const minDate = optionsConfig?.minDate;
|
|
7658
7687
|
const maxDate = optionsConfig?.maxDate;
|
|
7688
|
+
const minDateField = optionsConfig?.minDateField;
|
|
7689
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
7690
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
7691
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
7692
|
+
: undefined;
|
|
7693
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
7694
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
7695
|
+
: undefined;
|
|
7659
7696
|
const defaultToToday = widgetConfig['widget-data-default'] === 'today';
|
|
7660
|
-
// Track manual input value (for manual/hybrid modes)
|
|
7661
7697
|
const [manualInputValue, setManualInputValue] = useState('');
|
|
7662
7698
|
const [isFocused, setIsFocused] = useState(false);
|
|
7663
|
-
|
|
7699
|
+
const fieldMinDate = useMemo(() => {
|
|
7700
|
+
if (!minDateField) {
|
|
7701
|
+
return undefined;
|
|
7702
|
+
}
|
|
7703
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, minDateField));
|
|
7704
|
+
}, [formValues, minDateField]);
|
|
7705
|
+
const fieldMaxDate = useMemo(() => {
|
|
7706
|
+
if (!maxDateField) {
|
|
7707
|
+
return undefined;
|
|
7708
|
+
}
|
|
7709
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, maxDateField));
|
|
7710
|
+
}, [formValues, maxDateField]);
|
|
7711
|
+
const effectiveMinDate = useMemo(() => {
|
|
7712
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
7713
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
7714
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
7715
|
+
const effectiveMaxDate = useMemo(() => {
|
|
7716
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
7717
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
7718
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
7719
|
+
const constraintMessages = useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
7720
|
+
const runDateConstraintValidation = useCallback((dateValue) => {
|
|
7721
|
+
if (!dateValue) {
|
|
7722
|
+
return null;
|
|
7723
|
+
}
|
|
7724
|
+
return validateDateConstraints(dateValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
7725
|
+
}, [effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
7664
7726
|
useEffect(() => {
|
|
7665
7727
|
if (defaultToToday && (value === null || value === undefined || value === '')) {
|
|
7666
7728
|
const todayISO = formatDateToISO(new Date());
|
|
7667
7729
|
onChange(todayISO);
|
|
7668
7730
|
}
|
|
7669
7731
|
}, [defaultToToday, value, onChange]);
|
|
7670
|
-
//
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7732
|
+
// Re-validate when a relative bound field changes (e.g. start date set after end date)
|
|
7733
|
+
useEffect(() => {
|
|
7734
|
+
if (!value) {
|
|
7735
|
+
return;
|
|
7736
|
+
}
|
|
7737
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7738
|
+
if (constraintError) {
|
|
7739
|
+
setError([constraintError]);
|
|
7740
|
+
}
|
|
7741
|
+
}, [fieldMinDate, fieldMaxDate, value, runDateConstraintValidation, setError]);
|
|
7678
7742
|
const getDisplayValue = useCallback(() => {
|
|
7679
|
-
// For picker mode, always use YYYY-MM-DD
|
|
7680
7743
|
if (inputMethod === 'picker') {
|
|
7681
7744
|
if (!value)
|
|
7682
7745
|
return '';
|
|
7683
7746
|
return formatDateToISO(value);
|
|
7684
7747
|
}
|
|
7685
|
-
// For manual/hybrid modes, use custom format
|
|
7686
7748
|
if (isFocused && manualInputValue) {
|
|
7687
7749
|
return manualInputValue;
|
|
7688
7750
|
}
|
|
@@ -7693,7 +7755,6 @@ const DateInputWidget = ({ config }) => {
|
|
|
7693
7755
|
}
|
|
7694
7756
|
return formatDateToString(value, dateFormat);
|
|
7695
7757
|
}, [value, inputMethod, dateFormat, isFocused, manualInputValue]);
|
|
7696
|
-
// Initialize manual input value
|
|
7697
7758
|
useEffect(() => {
|
|
7698
7759
|
if (!isFocused && value) {
|
|
7699
7760
|
if (dateFormat === 'YYYY-MM-DD') {
|
|
@@ -7704,66 +7765,81 @@ const DateInputWidget = ({ config }) => {
|
|
|
7704
7765
|
}
|
|
7705
7766
|
}
|
|
7706
7767
|
}, [value, dateFormat, isFocused]);
|
|
7707
|
-
|
|
7768
|
+
const applyConstraintError = useCallback((dateValue) => {
|
|
7769
|
+
const constraintError = runDateConstraintValidation(dateValue);
|
|
7770
|
+
setError(constraintError ? [constraintError] : []);
|
|
7771
|
+
}, [runDateConstraintValidation, setError]);
|
|
7708
7772
|
const handleChange = useCallback((e) => {
|
|
7709
7773
|
const inputValue = e.target.value;
|
|
7710
7774
|
if (inputMethod === 'picker') {
|
|
7711
|
-
// Picker mode: input is always YYYY-MM-DD
|
|
7712
7775
|
if (inputValue) {
|
|
7713
7776
|
const date = parseDate(inputValue);
|
|
7714
7777
|
if (date) {
|
|
7715
|
-
|
|
7778
|
+
const iso = formatDateToISO(date);
|
|
7779
|
+
onChange(iso);
|
|
7780
|
+
applyConstraintError(iso);
|
|
7716
7781
|
}
|
|
7717
7782
|
else {
|
|
7718
7783
|
onChange('');
|
|
7784
|
+
setError([]);
|
|
7719
7785
|
}
|
|
7720
7786
|
}
|
|
7721
7787
|
else {
|
|
7722
7788
|
onChange('');
|
|
7789
|
+
setError([]);
|
|
7723
7790
|
}
|
|
7724
7791
|
}
|
|
7725
7792
|
else {
|
|
7726
|
-
// Manual/hybrid mode: parse custom format
|
|
7727
7793
|
setManualInputValue(inputValue);
|
|
7728
7794
|
if (inputValue) {
|
|
7729
7795
|
const date = parseDateFromFormat(inputValue, dateFormat);
|
|
7730
7796
|
if (date) {
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
onChange(formatDateToISO(date));
|
|
7735
|
-
}
|
|
7736
|
-
else {
|
|
7737
|
-
// Still update the value but validation will catch it
|
|
7738
|
-
onChange(formatDateToISO(date));
|
|
7739
|
-
}
|
|
7797
|
+
const iso = formatDateToISO(date);
|
|
7798
|
+
onChange(iso);
|
|
7799
|
+
applyConstraintError(iso);
|
|
7740
7800
|
}
|
|
7741
7801
|
}
|
|
7742
7802
|
else {
|
|
7743
7803
|
onChange('');
|
|
7804
|
+
setError([]);
|
|
7744
7805
|
}
|
|
7745
7806
|
}
|
|
7746
|
-
}, [inputMethod, dateFormat, onChange,
|
|
7747
|
-
// Handle blur - validate and format
|
|
7807
|
+
}, [inputMethod, dateFormat, onChange, applyConstraintError, setError]);
|
|
7748
7808
|
const handleBlur = useCallback(() => {
|
|
7749
7809
|
setIsFocused(false);
|
|
7750
7810
|
if (inputMethod !== 'picker' && manualInputValue) {
|
|
7751
7811
|
const date = parseDateFromFormat(manualInputValue, dateFormat);
|
|
7752
7812
|
if (date) {
|
|
7753
|
-
// Format the value according to the format
|
|
7754
7813
|
const formatted = formatDateToString(date, dateFormat);
|
|
7755
7814
|
setManualInputValue(formatted);
|
|
7756
|
-
|
|
7815
|
+
const iso = formatDateToISO(date);
|
|
7816
|
+
onChange(iso);
|
|
7817
|
+
applyConstraintError(iso);
|
|
7757
7818
|
}
|
|
7758
7819
|
else {
|
|
7759
|
-
// Invalid date, clear it
|
|
7760
7820
|
setManualInputValue('');
|
|
7761
7821
|
onChange('');
|
|
7822
|
+
setError([]);
|
|
7762
7823
|
}
|
|
7763
7824
|
}
|
|
7764
7825
|
onBlur();
|
|
7765
|
-
|
|
7766
|
-
|
|
7826
|
+
if (value) {
|
|
7827
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7828
|
+
if (constraintError) {
|
|
7829
|
+
setError([constraintError]);
|
|
7830
|
+
}
|
|
7831
|
+
}
|
|
7832
|
+
}, [
|
|
7833
|
+
inputMethod,
|
|
7834
|
+
manualInputValue,
|
|
7835
|
+
dateFormat,
|
|
7836
|
+
onChange,
|
|
7837
|
+
onBlur,
|
|
7838
|
+
applyConstraintError,
|
|
7839
|
+
value,
|
|
7840
|
+
runDateConstraintValidation,
|
|
7841
|
+
setError,
|
|
7842
|
+
]);
|
|
7767
7843
|
const handleFocus = useCallback(() => {
|
|
7768
7844
|
setIsFocused(true);
|
|
7769
7845
|
if (value) {
|
|
@@ -7775,15 +7851,15 @@ const DateInputWidget = ({ config }) => {
|
|
|
7775
7851
|
}
|
|
7776
7852
|
}
|
|
7777
7853
|
}, [value, dateFormat]);
|
|
7778
|
-
// Determine placeholder
|
|
7779
7854
|
const placeholder = useMemo(() => {
|
|
7780
|
-
const
|
|
7855
|
+
const display = getDisplayValue();
|
|
7856
|
+
const hasValue = display && display.trim().length > 0;
|
|
7781
7857
|
const placeholderText = translateConfig(widgetConfig['widget-data-placeholder']);
|
|
7782
|
-
return hasValue ? undefined :
|
|
7858
|
+
return hasValue ? undefined : placeholderText || dateFormat;
|
|
7783
7859
|
}, [getDisplayValue, widgetConfig, translateConfig, dateFormat]);
|
|
7784
|
-
// Determine input type
|
|
7785
7860
|
const inputType = inputMethod === 'picker' ? 'date' : 'text';
|
|
7786
|
-
|
|
7861
|
+
const showRequiredError = widgetConfig['widget-required'] && (!value || value === '');
|
|
7862
|
+
const showValidationError = touched && error.length > 0;
|
|
7787
7863
|
if (widgetConfig['widget-readonly']) {
|
|
7788
7864
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7789
7865
|
let displayValue = '';
|
|
@@ -7800,9 +7876,9 @@ const DateInputWidget = ({ config }) => {
|
|
|
7800
7876
|
}
|
|
7801
7877
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] DateDisplayWidget flex flex-col sm:flex-row sm:items-start", children: [label && (jsxRuntimeExports.jsxs("div", { className: "text-base text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: label, children: [label, ":"] })), jsxRuntimeExports.jsx("div", { className: "flex-1", children: jsxRuntimeExports.jsx("div", { className: "text-base text-gray-900 font-medium", title: String(displayValue ?? ''), children: displayValue }) })] }));
|
|
7802
7878
|
}
|
|
7803
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] &&
|
|
7879
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsx("input", { type: inputType, value: getDisplayValue(), onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: placeholder, min: inputMethod === 'picker' ? effectiveMinDate : undefined, max: inputMethod === 'picker' ? effectiveMaxDate : undefined, className: `w-full sm:w-[180px] max-w-full h-[30px] px-3 border shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${showValidationError || showRequiredError
|
|
7804
7880
|
? 'border-red-500 focus:ring-red-500 focus:border-red-500'
|
|
7805
|
-
: 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }),
|
|
7881
|
+
: 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }), showValidationError && jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] })] })] }) }));
|
|
7806
7882
|
};
|
|
7807
7883
|
|
|
7808
7884
|
/**
|
|
@@ -8746,16 +8822,70 @@ const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
|
8746
8822
|
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8747
8823
|
} }));
|
|
8748
8824
|
};
|
|
8749
|
-
const TableCellDate = ({ config, value, onValueChange }) => {
|
|
8825
|
+
const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
8826
|
+
const { translateConfig } = useWidgetTranslation();
|
|
8750
8827
|
const isReadonly = config['widget-readonly'] || false;
|
|
8751
8828
|
const placeholder = config['widget-data-placeholder'] || '';
|
|
8829
|
+
const optionsConfig = config['widget-data-options'];
|
|
8830
|
+
const formatConfig = config['widget-data-format'];
|
|
8831
|
+
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
8832
|
+
const minDate = optionsConfig?.minDate;
|
|
8833
|
+
const maxDate = optionsConfig?.maxDate;
|
|
8834
|
+
const minDateField = optionsConfig?.minDateField;
|
|
8835
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
8836
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
8837
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
8838
|
+
: undefined;
|
|
8839
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
8840
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
8841
|
+
: undefined;
|
|
8842
|
+
const [constraintError, setConstraintError] = useState(null);
|
|
8843
|
+
const resolveSiblingDate = (fieldRef) => {
|
|
8844
|
+
if (!fieldRef || !rowValues) {
|
|
8845
|
+
return undefined;
|
|
8846
|
+
}
|
|
8847
|
+
const raw = getValueByPath(rowValues, fieldRef) ?? rowValues[fieldRef];
|
|
8848
|
+
return resolveDateBoundFromFieldValue(raw);
|
|
8849
|
+
};
|
|
8850
|
+
const fieldMinDate = useMemo(() => resolveSiblingDate(minDateField), [minDateField, rowValues]);
|
|
8851
|
+
const fieldMaxDate = useMemo(() => resolveSiblingDate(maxDateField), [maxDateField, rowValues]);
|
|
8852
|
+
const effectiveMinDate = useMemo(() => {
|
|
8853
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
8854
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
8855
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
8856
|
+
const effectiveMaxDate = useMemo(() => {
|
|
8857
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
8858
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
8859
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
8860
|
+
const constraintMessages = useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
8752
8861
|
// input type="date" requires YYYY-MM-DD format
|
|
8753
8862
|
const displayValue = value && typeof value === 'string' ? value.split('T')[0] : '';
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
}
|
|
8863
|
+
useEffect(() => {
|
|
8864
|
+
if (!displayValue) {
|
|
8865
|
+
setConstraintError(null);
|
|
8866
|
+
return;
|
|
8867
|
+
}
|
|
8868
|
+
const error = validateDateConstraints(displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8869
|
+
setConstraintError(error);
|
|
8870
|
+
}, [displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
8871
|
+
const handleChange = (e) => {
|
|
8872
|
+
const nextValue = e.target.value;
|
|
8873
|
+
onValueChange(nextValue);
|
|
8874
|
+
if (!nextValue) {
|
|
8875
|
+
setConstraintError(null);
|
|
8876
|
+
return;
|
|
8877
|
+
}
|
|
8878
|
+
const error = validateDateConstraints(nextValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8879
|
+
setConstraintError(error);
|
|
8880
|
+
};
|
|
8881
|
+
const hasError = Boolean(constraintError);
|
|
8882
|
+
return (jsxRuntimeExports.jsxs("div", { className: "w-full", children: [jsxRuntimeExports.jsx("input", { type: "date", value: displayValue, onChange: handleChange, disabled: isReadonly, placeholder: placeholder, min: effectiveMinDate, max: effectiveMaxDate, title: constraintError || translateConfig(config['widget-data-tooltip']), className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly ? 'cursor-not-allowed' : ''} ${hasError ? 'border-red-500' : ''} table-cell-input`, style: {
|
|
8883
|
+
borderRadius: '10px',
|
|
8884
|
+
borderColor: hasError
|
|
8885
|
+
? 'var(--owt-color-error, #B91C1C)'
|
|
8886
|
+
: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8887
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8888
|
+
} }), hasError && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-xs mt-0.5 leading-tight", children: constraintError }))] }));
|
|
8759
8889
|
};
|
|
8760
8890
|
const TableWidget = ({ config }) => {
|
|
8761
8891
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
|
|
@@ -9114,11 +9244,21 @@ const TableWidget = ({ config }) => {
|
|
|
9114
9244
|
});
|
|
9115
9245
|
}
|
|
9116
9246
|
}, [isAdding, newRowData, columns, widgetConfig, rows.length, dispatch]);
|
|
9247
|
+
const getRowValuesForEdit = useCallback((rowIndex) => {
|
|
9248
|
+
if (editingState && editingState.rowIndex === rowIndex) {
|
|
9249
|
+
return editingState.currentValue ?? {};
|
|
9250
|
+
}
|
|
9251
|
+
if (isAdding && rowIndex === rows.length && newRowData) {
|
|
9252
|
+
return newRowData;
|
|
9253
|
+
}
|
|
9254
|
+
return rows[rowIndex] ?? {};
|
|
9255
|
+
}, [editingState, isAdding, rows, newRowData]);
|
|
9117
9256
|
// Lightweight cell renderer for table cells (no labels, compact)
|
|
9118
9257
|
const renderTableCell = useCallback((rowIndex, column, cellValue, isReadonly) => {
|
|
9119
9258
|
const columnKey = column['column-key'];
|
|
9120
9259
|
const widgetType = column.widget || 'text';
|
|
9121
9260
|
const cellWidgetId = `${widgetConfig['widget-id']}-row-${rowIndex}-col-${columnKey}`;
|
|
9261
|
+
const rowValues = getRowValuesForEdit(rowIndex);
|
|
9122
9262
|
// Use lightweight cell config (no label, minimal styling)
|
|
9123
9263
|
const cellConfig = {
|
|
9124
9264
|
...column,
|
|
@@ -9141,7 +9281,7 @@ const TableWidget = ({ config }) => {
|
|
|
9141
9281
|
return jsxRuntimeExports.jsx(TableCellNumber, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9142
9282
|
}
|
|
9143
9283
|
else if (widgetType === 'date') {
|
|
9144
|
-
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9284
|
+
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, rowValues: rowValues, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9145
9285
|
}
|
|
9146
9286
|
// For other widget types, use WidgetRenderer but with compact styling
|
|
9147
9287
|
return (jsxRuntimeExports.jsx("div", { className: "table-cell-widget", style: { margin: 0, padding: 0 }, children: jsxRuntimeExports.jsx(WidgetRenderer, { config: cellConfig, schemaData: {
|
|
@@ -9149,7 +9289,7 @@ const TableWidget = ({ config }) => {
|
|
|
9149
9289
|
}, onValueChange: (widgetId, newValue) => {
|
|
9150
9290
|
updateCellValue(columnKey, newValue, rowIndex);
|
|
9151
9291
|
} }) }));
|
|
9152
|
-
}, [widgetConfig, updateCellValue]);
|
|
9292
|
+
}, [widgetConfig, updateCellValue, getRowValuesForEdit]);
|
|
9153
9293
|
// Render cell content (widget in edit mode, formatted value in view mode)
|
|
9154
9294
|
const renderCell = useCallback((rowIndex, column, row) => {
|
|
9155
9295
|
const columnKey = column['column-key'];
|