@openg2p/registry-widgets 1.1.0-dev.13 → 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 +6 -1
- package/LICENSE +0 -373
- package/README.md +0 -433
- package/dist/events/types.d.ts +0 -27
- package/dist/events/types.d.ts.map +0 -1
- package/dist/index.css +0 -4
- package/dist/index.css.map +0 -1
package/dist/index.js
CHANGED
|
@@ -808,6 +808,40 @@ const parseDateFromFormat = (dateString, format) => {
|
|
|
808
808
|
}
|
|
809
809
|
return parseDate(dateString);
|
|
810
810
|
};
|
|
811
|
+
/**
|
|
812
|
+
* Resolve a stored date value (ISO or parseable string) to YYYY-MM-DD for comparisons.
|
|
813
|
+
*/
|
|
814
|
+
const resolveDateBoundFromFieldValue = (fieldValue) => {
|
|
815
|
+
if (fieldValue == null || fieldValue === '') {
|
|
816
|
+
return undefined;
|
|
817
|
+
}
|
|
818
|
+
const iso = formatDateToISO(fieldValue);
|
|
819
|
+
return iso || undefined;
|
|
820
|
+
};
|
|
821
|
+
/**
|
|
822
|
+
* Pick the stricter (later) minimum when combining static and field-based bounds.
|
|
823
|
+
*/
|
|
824
|
+
const mergeMinDateBounds = (boundA, boundB) => {
|
|
825
|
+
if (!boundA) {
|
|
826
|
+
return boundB;
|
|
827
|
+
}
|
|
828
|
+
if (!boundB) {
|
|
829
|
+
return boundA;
|
|
830
|
+
}
|
|
831
|
+
return boundA > boundB ? boundA : boundB;
|
|
832
|
+
};
|
|
833
|
+
/**
|
|
834
|
+
* Pick the stricter (earlier) maximum when combining static and field-based bounds.
|
|
835
|
+
*/
|
|
836
|
+
const mergeMaxDateBounds = (boundA, boundB) => {
|
|
837
|
+
if (!boundA) {
|
|
838
|
+
return boundB;
|
|
839
|
+
}
|
|
840
|
+
if (!boundB) {
|
|
841
|
+
return boundA;
|
|
842
|
+
}
|
|
843
|
+
return boundA < boundB ? boundA : boundB;
|
|
844
|
+
};
|
|
811
845
|
/**
|
|
812
846
|
* Get min date based on constraint type
|
|
813
847
|
*/
|
|
@@ -850,10 +884,7 @@ const getMaxDate = (constraint, maxDate) => {
|
|
|
850
884
|
}
|
|
851
885
|
return undefined;
|
|
852
886
|
};
|
|
853
|
-
|
|
854
|
-
* Validate date constraints
|
|
855
|
-
*/
|
|
856
|
-
const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
887
|
+
const validateDateConstraints = (date, minDate, maxDate, constraint, messages) => {
|
|
857
888
|
if (!date)
|
|
858
889
|
return null;
|
|
859
890
|
const dateObj = date instanceof Date ? date : parseDate(date);
|
|
@@ -872,15 +903,12 @@ const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
|
872
903
|
return 'Date must be in the future';
|
|
873
904
|
}
|
|
874
905
|
}
|
|
875
|
-
//
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
return `Date must be on or after ${effectiveMinDate}`;
|
|
906
|
+
// minDate / maxDate are effective bounds (static + field-based), resolved by the caller
|
|
907
|
+
if (minDate && dateISO < minDate) {
|
|
908
|
+
return messages?.minDateMessage ?? `Date must be on or after ${minDate}`;
|
|
879
909
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
if (effectiveMaxDate && dateISO > effectiveMaxDate) {
|
|
883
|
-
return `Date must be on or before ${effectiveMaxDate}`;
|
|
910
|
+
if (maxDate && dateISO > maxDate) {
|
|
911
|
+
return messages?.maxDateMessage ?? `Date must be on or before ${maxDate}`;
|
|
884
912
|
}
|
|
885
913
|
return null;
|
|
886
914
|
};
|
|
@@ -7648,42 +7676,76 @@ const BooleanWidget = ({ config }) => {
|
|
|
7648
7676
|
};
|
|
7649
7677
|
|
|
7650
7678
|
const DateInputWidget = ({ config }) => {
|
|
7651
|
-
const { value,
|
|
7652
|
-
const
|
|
7679
|
+
const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
|
|
7680
|
+
const formValues = reactRedux.useSelector((state) => state.widget.values);
|
|
7681
|
+
const { translateConfig } = useWidgetTranslation();
|
|
7653
7682
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7654
7683
|
const optionsConfig = widgetConfig['widget-data-options'];
|
|
7655
7684
|
const dateFormat = formatConfig?.dateFormat || 'YYYY-MM-DD';
|
|
7656
|
-
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7685
|
+
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7657
7686
|
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
7658
7687
|
const minDate = optionsConfig?.minDate;
|
|
7659
7688
|
const maxDate = optionsConfig?.maxDate;
|
|
7689
|
+
const minDateField = optionsConfig?.minDateField;
|
|
7690
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
7691
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
7692
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
7693
|
+
: undefined;
|
|
7694
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
7695
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
7696
|
+
: undefined;
|
|
7660
7697
|
const defaultToToday = widgetConfig['widget-data-default'] === 'today';
|
|
7661
|
-
// Track manual input value (for manual/hybrid modes)
|
|
7662
7698
|
const [manualInputValue, setManualInputValue] = React.useState('');
|
|
7663
7699
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
7664
|
-
|
|
7700
|
+
const fieldMinDate = React.useMemo(() => {
|
|
7701
|
+
if (!minDateField) {
|
|
7702
|
+
return undefined;
|
|
7703
|
+
}
|
|
7704
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, minDateField));
|
|
7705
|
+
}, [formValues, minDateField]);
|
|
7706
|
+
const fieldMaxDate = React.useMemo(() => {
|
|
7707
|
+
if (!maxDateField) {
|
|
7708
|
+
return undefined;
|
|
7709
|
+
}
|
|
7710
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, maxDateField));
|
|
7711
|
+
}, [formValues, maxDateField]);
|
|
7712
|
+
const effectiveMinDate = React.useMemo(() => {
|
|
7713
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
7714
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
7715
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
7716
|
+
const effectiveMaxDate = React.useMemo(() => {
|
|
7717
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
7718
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
7719
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
7720
|
+
const constraintMessages = React.useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
7721
|
+
const runDateConstraintValidation = React.useCallback((dateValue) => {
|
|
7722
|
+
if (!dateValue) {
|
|
7723
|
+
return null;
|
|
7724
|
+
}
|
|
7725
|
+
return validateDateConstraints(dateValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
7726
|
+
}, [effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
7665
7727
|
React.useEffect(() => {
|
|
7666
7728
|
if (defaultToToday && (value === null || value === undefined || value === '')) {
|
|
7667
7729
|
const todayISO = formatDateToISO(new Date());
|
|
7668
7730
|
onChange(todayISO);
|
|
7669
7731
|
}
|
|
7670
7732
|
}, [defaultToToday, value, onChange]);
|
|
7671
|
-
//
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7733
|
+
// Re-validate when a relative bound field changes (e.g. start date set after end date)
|
|
7734
|
+
React.useEffect(() => {
|
|
7735
|
+
if (!value) {
|
|
7736
|
+
return;
|
|
7737
|
+
}
|
|
7738
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7739
|
+
if (constraintError) {
|
|
7740
|
+
setError([constraintError]);
|
|
7741
|
+
}
|
|
7742
|
+
}, [fieldMinDate, fieldMaxDate, value, runDateConstraintValidation, setError]);
|
|
7679
7743
|
const getDisplayValue = React.useCallback(() => {
|
|
7680
|
-
// For picker mode, always use YYYY-MM-DD
|
|
7681
7744
|
if (inputMethod === 'picker') {
|
|
7682
7745
|
if (!value)
|
|
7683
7746
|
return '';
|
|
7684
7747
|
return formatDateToISO(value);
|
|
7685
7748
|
}
|
|
7686
|
-
// For manual/hybrid modes, use custom format
|
|
7687
7749
|
if (isFocused && manualInputValue) {
|
|
7688
7750
|
return manualInputValue;
|
|
7689
7751
|
}
|
|
@@ -7694,7 +7756,6 @@ const DateInputWidget = ({ config }) => {
|
|
|
7694
7756
|
}
|
|
7695
7757
|
return formatDateToString(value, dateFormat);
|
|
7696
7758
|
}, [value, inputMethod, dateFormat, isFocused, manualInputValue]);
|
|
7697
|
-
// Initialize manual input value
|
|
7698
7759
|
React.useEffect(() => {
|
|
7699
7760
|
if (!isFocused && value) {
|
|
7700
7761
|
if (dateFormat === 'YYYY-MM-DD') {
|
|
@@ -7705,66 +7766,81 @@ const DateInputWidget = ({ config }) => {
|
|
|
7705
7766
|
}
|
|
7706
7767
|
}
|
|
7707
7768
|
}, [value, dateFormat, isFocused]);
|
|
7708
|
-
|
|
7769
|
+
const applyConstraintError = React.useCallback((dateValue) => {
|
|
7770
|
+
const constraintError = runDateConstraintValidation(dateValue);
|
|
7771
|
+
setError(constraintError ? [constraintError] : []);
|
|
7772
|
+
}, [runDateConstraintValidation, setError]);
|
|
7709
7773
|
const handleChange = React.useCallback((e) => {
|
|
7710
7774
|
const inputValue = e.target.value;
|
|
7711
7775
|
if (inputMethod === 'picker') {
|
|
7712
|
-
// Picker mode: input is always YYYY-MM-DD
|
|
7713
7776
|
if (inputValue) {
|
|
7714
7777
|
const date = parseDate(inputValue);
|
|
7715
7778
|
if (date) {
|
|
7716
|
-
|
|
7779
|
+
const iso = formatDateToISO(date);
|
|
7780
|
+
onChange(iso);
|
|
7781
|
+
applyConstraintError(iso);
|
|
7717
7782
|
}
|
|
7718
7783
|
else {
|
|
7719
7784
|
onChange('');
|
|
7785
|
+
setError([]);
|
|
7720
7786
|
}
|
|
7721
7787
|
}
|
|
7722
7788
|
else {
|
|
7723
7789
|
onChange('');
|
|
7790
|
+
setError([]);
|
|
7724
7791
|
}
|
|
7725
7792
|
}
|
|
7726
7793
|
else {
|
|
7727
|
-
// Manual/hybrid mode: parse custom format
|
|
7728
7794
|
setManualInputValue(inputValue);
|
|
7729
7795
|
if (inputValue) {
|
|
7730
7796
|
const date = parseDateFromFormat(inputValue, dateFormat);
|
|
7731
7797
|
if (date) {
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
onChange(formatDateToISO(date));
|
|
7736
|
-
}
|
|
7737
|
-
else {
|
|
7738
|
-
// Still update the value but validation will catch it
|
|
7739
|
-
onChange(formatDateToISO(date));
|
|
7740
|
-
}
|
|
7798
|
+
const iso = formatDateToISO(date);
|
|
7799
|
+
onChange(iso);
|
|
7800
|
+
applyConstraintError(iso);
|
|
7741
7801
|
}
|
|
7742
7802
|
}
|
|
7743
7803
|
else {
|
|
7744
7804
|
onChange('');
|
|
7805
|
+
setError([]);
|
|
7745
7806
|
}
|
|
7746
7807
|
}
|
|
7747
|
-
}, [inputMethod, dateFormat, onChange,
|
|
7748
|
-
// Handle blur - validate and format
|
|
7808
|
+
}, [inputMethod, dateFormat, onChange, applyConstraintError, setError]);
|
|
7749
7809
|
const handleBlur = React.useCallback(() => {
|
|
7750
7810
|
setIsFocused(false);
|
|
7751
7811
|
if (inputMethod !== 'picker' && manualInputValue) {
|
|
7752
7812
|
const date = parseDateFromFormat(manualInputValue, dateFormat);
|
|
7753
7813
|
if (date) {
|
|
7754
|
-
// Format the value according to the format
|
|
7755
7814
|
const formatted = formatDateToString(date, dateFormat);
|
|
7756
7815
|
setManualInputValue(formatted);
|
|
7757
|
-
|
|
7816
|
+
const iso = formatDateToISO(date);
|
|
7817
|
+
onChange(iso);
|
|
7818
|
+
applyConstraintError(iso);
|
|
7758
7819
|
}
|
|
7759
7820
|
else {
|
|
7760
|
-
// Invalid date, clear it
|
|
7761
7821
|
setManualInputValue('');
|
|
7762
7822
|
onChange('');
|
|
7823
|
+
setError([]);
|
|
7763
7824
|
}
|
|
7764
7825
|
}
|
|
7765
7826
|
onBlur();
|
|
7766
|
-
|
|
7767
|
-
|
|
7827
|
+
if (value) {
|
|
7828
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7829
|
+
if (constraintError) {
|
|
7830
|
+
setError([constraintError]);
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
}, [
|
|
7834
|
+
inputMethod,
|
|
7835
|
+
manualInputValue,
|
|
7836
|
+
dateFormat,
|
|
7837
|
+
onChange,
|
|
7838
|
+
onBlur,
|
|
7839
|
+
applyConstraintError,
|
|
7840
|
+
value,
|
|
7841
|
+
runDateConstraintValidation,
|
|
7842
|
+
setError,
|
|
7843
|
+
]);
|
|
7768
7844
|
const handleFocus = React.useCallback(() => {
|
|
7769
7845
|
setIsFocused(true);
|
|
7770
7846
|
if (value) {
|
|
@@ -7776,15 +7852,15 @@ const DateInputWidget = ({ config }) => {
|
|
|
7776
7852
|
}
|
|
7777
7853
|
}
|
|
7778
7854
|
}, [value, dateFormat]);
|
|
7779
|
-
// Determine placeholder
|
|
7780
7855
|
const placeholder = React.useMemo(() => {
|
|
7781
|
-
const
|
|
7856
|
+
const display = getDisplayValue();
|
|
7857
|
+
const hasValue = display && display.trim().length > 0;
|
|
7782
7858
|
const placeholderText = translateConfig(widgetConfig['widget-data-placeholder']);
|
|
7783
|
-
return hasValue ? undefined :
|
|
7859
|
+
return hasValue ? undefined : placeholderText || dateFormat;
|
|
7784
7860
|
}, [getDisplayValue, widgetConfig, translateConfig, dateFormat]);
|
|
7785
|
-
// Determine input type
|
|
7786
7861
|
const inputType = inputMethod === 'picker' ? 'date' : 'text';
|
|
7787
|
-
|
|
7862
|
+
const showRequiredError = widgetConfig['widget-required'] && (!value || value === '');
|
|
7863
|
+
const showValidationError = touched && error.length > 0;
|
|
7788
7864
|
if (widgetConfig['widget-readonly']) {
|
|
7789
7865
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7790
7866
|
let displayValue = '';
|
|
@@ -7801,9 +7877,9 @@ const DateInputWidget = ({ config }) => {
|
|
|
7801
7877
|
}
|
|
7802
7878
|
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 }) })] }));
|
|
7803
7879
|
}
|
|
7804
|
-
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'] &&
|
|
7880
|
+
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
|
|
7805
7881
|
? 'border-red-500 focus:ring-red-500 focus:border-red-500'
|
|
7806
|
-
: 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }),
|
|
7882
|
+
: '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] })] })] }) }));
|
|
7807
7883
|
};
|
|
7808
7884
|
|
|
7809
7885
|
/**
|
|
@@ -8747,16 +8823,70 @@ const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
|
8747
8823
|
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8748
8824
|
} }));
|
|
8749
8825
|
};
|
|
8750
|
-
const TableCellDate = ({ config, value, onValueChange }) => {
|
|
8826
|
+
const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
8827
|
+
const { translateConfig } = useWidgetTranslation();
|
|
8751
8828
|
const isReadonly = config['widget-readonly'] || false;
|
|
8752
8829
|
const placeholder = config['widget-data-placeholder'] || '';
|
|
8830
|
+
const optionsConfig = config['widget-data-options'];
|
|
8831
|
+
const formatConfig = config['widget-data-format'];
|
|
8832
|
+
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
8833
|
+
const minDate = optionsConfig?.minDate;
|
|
8834
|
+
const maxDate = optionsConfig?.maxDate;
|
|
8835
|
+
const minDateField = optionsConfig?.minDateField;
|
|
8836
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
8837
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
8838
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
8839
|
+
: undefined;
|
|
8840
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
8841
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
8842
|
+
: undefined;
|
|
8843
|
+
const [constraintError, setConstraintError] = React.useState(null);
|
|
8844
|
+
const resolveSiblingDate = (fieldRef) => {
|
|
8845
|
+
if (!fieldRef || !rowValues) {
|
|
8846
|
+
return undefined;
|
|
8847
|
+
}
|
|
8848
|
+
const raw = getValueByPath(rowValues, fieldRef) ?? rowValues[fieldRef];
|
|
8849
|
+
return resolveDateBoundFromFieldValue(raw);
|
|
8850
|
+
};
|
|
8851
|
+
const fieldMinDate = React.useMemo(() => resolveSiblingDate(minDateField), [minDateField, rowValues]);
|
|
8852
|
+
const fieldMaxDate = React.useMemo(() => resolveSiblingDate(maxDateField), [maxDateField, rowValues]);
|
|
8853
|
+
const effectiveMinDate = React.useMemo(() => {
|
|
8854
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
8855
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
8856
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
8857
|
+
const effectiveMaxDate = React.useMemo(() => {
|
|
8858
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
8859
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
8860
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
8861
|
+
const constraintMessages = React.useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
8753
8862
|
// input type="date" requires YYYY-MM-DD format
|
|
8754
8863
|
const displayValue = value && typeof value === 'string' ? value.split('T')[0] : '';
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
}
|
|
8864
|
+
React.useEffect(() => {
|
|
8865
|
+
if (!displayValue) {
|
|
8866
|
+
setConstraintError(null);
|
|
8867
|
+
return;
|
|
8868
|
+
}
|
|
8869
|
+
const error = validateDateConstraints(displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8870
|
+
setConstraintError(error);
|
|
8871
|
+
}, [displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
8872
|
+
const handleChange = (e) => {
|
|
8873
|
+
const nextValue = e.target.value;
|
|
8874
|
+
onValueChange(nextValue);
|
|
8875
|
+
if (!nextValue) {
|
|
8876
|
+
setConstraintError(null);
|
|
8877
|
+
return;
|
|
8878
|
+
}
|
|
8879
|
+
const error = validateDateConstraints(nextValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8880
|
+
setConstraintError(error);
|
|
8881
|
+
};
|
|
8882
|
+
const hasError = Boolean(constraintError);
|
|
8883
|
+
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: {
|
|
8884
|
+
borderRadius: '10px',
|
|
8885
|
+
borderColor: hasError
|
|
8886
|
+
? 'var(--owt-color-error, #B91C1C)'
|
|
8887
|
+
: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8888
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8889
|
+
} }), hasError && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-xs mt-0.5 leading-tight", children: constraintError }))] }));
|
|
8760
8890
|
};
|
|
8761
8891
|
const TableWidget = ({ config }) => {
|
|
8762
8892
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
|
|
@@ -9115,11 +9245,21 @@ const TableWidget = ({ config }) => {
|
|
|
9115
9245
|
});
|
|
9116
9246
|
}
|
|
9117
9247
|
}, [isAdding, newRowData, columns, widgetConfig, rows.length, dispatch]);
|
|
9248
|
+
const getRowValuesForEdit = React.useCallback((rowIndex) => {
|
|
9249
|
+
if (editingState && editingState.rowIndex === rowIndex) {
|
|
9250
|
+
return editingState.currentValue ?? {};
|
|
9251
|
+
}
|
|
9252
|
+
if (isAdding && rowIndex === rows.length && newRowData) {
|
|
9253
|
+
return newRowData;
|
|
9254
|
+
}
|
|
9255
|
+
return rows[rowIndex] ?? {};
|
|
9256
|
+
}, [editingState, isAdding, rows, newRowData]);
|
|
9118
9257
|
// Lightweight cell renderer for table cells (no labels, compact)
|
|
9119
9258
|
const renderTableCell = React.useCallback((rowIndex, column, cellValue, isReadonly) => {
|
|
9120
9259
|
const columnKey = column['column-key'];
|
|
9121
9260
|
const widgetType = column.widget || 'text';
|
|
9122
9261
|
const cellWidgetId = `${widgetConfig['widget-id']}-row-${rowIndex}-col-${columnKey}`;
|
|
9262
|
+
const rowValues = getRowValuesForEdit(rowIndex);
|
|
9123
9263
|
// Use lightweight cell config (no label, minimal styling)
|
|
9124
9264
|
const cellConfig = {
|
|
9125
9265
|
...column,
|
|
@@ -9142,7 +9282,7 @@ const TableWidget = ({ config }) => {
|
|
|
9142
9282
|
return jsxRuntimeExports.jsx(TableCellNumber, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9143
9283
|
}
|
|
9144
9284
|
else if (widgetType === 'date') {
|
|
9145
|
-
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9285
|
+
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, rowValues: rowValues, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9146
9286
|
}
|
|
9147
9287
|
// For other widget types, use WidgetRenderer but with compact styling
|
|
9148
9288
|
return (jsxRuntimeExports.jsx("div", { className: "table-cell-widget", style: { margin: 0, padding: 0 }, children: jsxRuntimeExports.jsx(WidgetRenderer, { config: cellConfig, schemaData: {
|
|
@@ -9150,7 +9290,7 @@ const TableWidget = ({ config }) => {
|
|
|
9150
9290
|
}, onValueChange: (widgetId, newValue) => {
|
|
9151
9291
|
updateCellValue(columnKey, newValue, rowIndex);
|
|
9152
9292
|
} }) }));
|
|
9153
|
-
}, [widgetConfig, updateCellValue]);
|
|
9293
|
+
}, [widgetConfig, updateCellValue, getRowValuesForEdit]);
|
|
9154
9294
|
// Render cell content (widget in edit mode, formatted value in view mode)
|
|
9155
9295
|
const renderCell = React.useCallback((rowIndex, column, row) => {
|
|
9156
9296
|
const columnKey = column['column-key'];
|