@openg2p/registry-widgets 1.1.0 → 1.1.2-dev.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/components/SectionBuilder/schemas.d.ts +48 -0
- package/dist/components/SectionBuilder/schemas.d.ts.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.esm.js +413 -128
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +412 -126
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +6 -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/utils/numberInput.d.ts +1 -0
- package/dist/utils/numberInput.d.ts.map +1 -1
- package/dist/utils/sectionValidate.d.ts.map +1 -1
- package/dist/widgets/BooleanWidget.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/DialogTableWidget.d.ts.map +1 -1
- package/dist/widgets/HeaderSectionWidget.d.ts.map +1 -1
- package/dist/widgets/NumberInputWidget.d.ts +2 -0
- package/dist/widgets/NumberInputWidget.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.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSlice, configureStore } from '@reduxjs/toolkit';
|
|
2
|
-
import React, { useContext, createContext, useMemo, useEffect, useRef, useCallback, useState } from 'react';
|
|
2
|
+
import React, { useContext, createContext, useMemo, useEffect, useRef, useCallback, useState, useId } from 'react';
|
|
3
3
|
import { Provider, useDispatch, useSelector, useStore } from 'react-redux';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
@@ -672,6 +672,21 @@ const getFormattedNumberLength = (value, format) => {
|
|
|
672
672
|
const formatted = formatNumber(typeof value === 'string' ? parseFloat(value) : value, format);
|
|
673
673
|
return formatted.length;
|
|
674
674
|
};
|
|
675
|
+
const normalizeNumericDefault = (defaultValue, format) => {
|
|
676
|
+
if (defaultValue === undefined) {
|
|
677
|
+
return undefined;
|
|
678
|
+
}
|
|
679
|
+
if (defaultValue === null || defaultValue === '') {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
const numValue = typeof defaultValue === 'number'
|
|
683
|
+
? defaultValue
|
|
684
|
+
: parseNumber(String(defaultValue), format);
|
|
685
|
+
if (numValue === null || isNaN(numValue)) {
|
|
686
|
+
return undefined;
|
|
687
|
+
}
|
|
688
|
+
return applyDecimalPrecision(numValue, format);
|
|
689
|
+
};
|
|
675
690
|
|
|
676
691
|
/**
|
|
677
692
|
* Date input utilities for parsing, formatting, and validation
|
|
@@ -807,6 +822,40 @@ const parseDateFromFormat = (dateString, format) => {
|
|
|
807
822
|
}
|
|
808
823
|
return parseDate(dateString);
|
|
809
824
|
};
|
|
825
|
+
/**
|
|
826
|
+
* Resolve a stored date value (ISO or parseable string) to YYYY-MM-DD for comparisons.
|
|
827
|
+
*/
|
|
828
|
+
const resolveDateBoundFromFieldValue = (fieldValue) => {
|
|
829
|
+
if (fieldValue == null || fieldValue === '') {
|
|
830
|
+
return undefined;
|
|
831
|
+
}
|
|
832
|
+
const iso = formatDateToISO(fieldValue);
|
|
833
|
+
return iso || undefined;
|
|
834
|
+
};
|
|
835
|
+
/**
|
|
836
|
+
* Pick the stricter (later) minimum when combining static and field-based bounds.
|
|
837
|
+
*/
|
|
838
|
+
const mergeMinDateBounds = (boundA, boundB) => {
|
|
839
|
+
if (!boundA) {
|
|
840
|
+
return boundB;
|
|
841
|
+
}
|
|
842
|
+
if (!boundB) {
|
|
843
|
+
return boundA;
|
|
844
|
+
}
|
|
845
|
+
return boundA > boundB ? boundA : boundB;
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Pick the stricter (earlier) maximum when combining static and field-based bounds.
|
|
849
|
+
*/
|
|
850
|
+
const mergeMaxDateBounds = (boundA, boundB) => {
|
|
851
|
+
if (!boundA) {
|
|
852
|
+
return boundB;
|
|
853
|
+
}
|
|
854
|
+
if (!boundB) {
|
|
855
|
+
return boundA;
|
|
856
|
+
}
|
|
857
|
+
return boundA < boundB ? boundA : boundB;
|
|
858
|
+
};
|
|
810
859
|
/**
|
|
811
860
|
* Get min date based on constraint type
|
|
812
861
|
*/
|
|
@@ -849,10 +898,7 @@ const getMaxDate = (constraint, maxDate) => {
|
|
|
849
898
|
}
|
|
850
899
|
return undefined;
|
|
851
900
|
};
|
|
852
|
-
|
|
853
|
-
* Validate date constraints
|
|
854
|
-
*/
|
|
855
|
-
const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
901
|
+
const validateDateConstraints = (date, minDate, maxDate, constraint, messages) => {
|
|
856
902
|
if (!date)
|
|
857
903
|
return null;
|
|
858
904
|
const dateObj = date instanceof Date ? date : parseDate(date);
|
|
@@ -871,15 +917,12 @@ const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
|
871
917
|
return 'Date must be in the future';
|
|
872
918
|
}
|
|
873
919
|
}
|
|
874
|
-
//
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
return `Date must be on or after ${effectiveMinDate}`;
|
|
920
|
+
// minDate / maxDate are effective bounds (static + field-based), resolved by the caller
|
|
921
|
+
if (minDate && dateISO < minDate) {
|
|
922
|
+
return messages?.minDateMessage ?? `Date must be on or after ${minDate}`;
|
|
878
923
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
if (effectiveMaxDate && dateISO > effectiveMaxDate) {
|
|
882
|
-
return `Date must be on or before ${effectiveMaxDate}`;
|
|
924
|
+
if (maxDate && dateISO > maxDate) {
|
|
925
|
+
return messages?.maxDateMessage ?? `Date must be on or before ${maxDate}`;
|
|
883
926
|
}
|
|
884
927
|
return null;
|
|
885
928
|
};
|
|
@@ -3793,6 +3836,116 @@ const namespaceSectionConfig = (section, namespace) => {
|
|
|
3793
3836
|
return namespaced;
|
|
3794
3837
|
};
|
|
3795
3838
|
|
|
3839
|
+
/** Table-style widgets that bind to an array path in the store / schema. */
|
|
3840
|
+
function isTableLikeWidget(widget) {
|
|
3841
|
+
const w = widget.widget;
|
|
3842
|
+
/** widget-type union in types omits legacy values like simple-table still used at runtime */
|
|
3843
|
+
const t = widget['widget-type'];
|
|
3844
|
+
return (w === 'table' ||
|
|
3845
|
+
w === 'dialog-table' ||
|
|
3846
|
+
w === 'simple-table' ||
|
|
3847
|
+
t === 'table' ||
|
|
3848
|
+
t === 'simple-table');
|
|
3849
|
+
}
|
|
3850
|
+
/**
|
|
3851
|
+
* Resolve `records` for section save payloads.
|
|
3852
|
+
* - Back-compat: path ending in `.records` (e.g. `regId.records`)
|
|
3853
|
+
* - Else: first array snapshot at a string `widget-data-path` on a table-like widget
|
|
3854
|
+
* (e.g. `household.members` for dialog-table)
|
|
3855
|
+
*/
|
|
3856
|
+
function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
|
|
3857
|
+
const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
|
|
3858
|
+
if (convention) {
|
|
3859
|
+
return convention[1];
|
|
3860
|
+
}
|
|
3861
|
+
const tablePaths = [];
|
|
3862
|
+
sectionWidgets.forEach((widget) => {
|
|
3863
|
+
if (!isTableLikeWidget(widget))
|
|
3864
|
+
return;
|
|
3865
|
+
const p = widget['widget-data-path'];
|
|
3866
|
+
if (typeof p === 'string' && p.length > 0) {
|
|
3867
|
+
tablePaths.push(p);
|
|
3868
|
+
}
|
|
3869
|
+
else if (p && typeof p === 'object') {
|
|
3870
|
+
Object.values(p).forEach((sub) => {
|
|
3871
|
+
if (typeof sub === 'string' && sub.length > 0)
|
|
3872
|
+
tablePaths.push(sub);
|
|
3873
|
+
});
|
|
3874
|
+
}
|
|
3875
|
+
});
|
|
3876
|
+
for (const path of tablePaths) {
|
|
3877
|
+
const val = snapshot[path];
|
|
3878
|
+
if (Array.isArray(val)) {
|
|
3879
|
+
return val;
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
return [];
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
const isColumnRequired = (column, skipRequired) => {
|
|
3886
|
+
if (skipRequired)
|
|
3887
|
+
return false;
|
|
3888
|
+
const validation = column['widget-data-validation'];
|
|
3889
|
+
return !!(column['widget-required'] || validation?.required);
|
|
3890
|
+
};
|
|
3891
|
+
const validateTableLikeWidget = (widget, currentSchemaData, dispatch, skipRequired) => {
|
|
3892
|
+
const widgetId = widget['widget-id'];
|
|
3893
|
+
if (!widgetId)
|
|
3894
|
+
return true;
|
|
3895
|
+
const columns = (widget['widget-data-columns'] || []);
|
|
3896
|
+
const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
|
|
3897
|
+
const rows = Array.isArray(value)
|
|
3898
|
+
? value
|
|
3899
|
+
: [];
|
|
3900
|
+
const activeRows = rows.filter((row) => row?.edit_action !== 'DELETE');
|
|
3901
|
+
const rowErrors = [];
|
|
3902
|
+
let isValid = true;
|
|
3903
|
+
if (!skipRequired && widget['widget-required'] && activeRows.length === 0) {
|
|
3904
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3905
|
+
dispatch(setError({ widgetId, errors: ['At least one record is required'] }));
|
|
3906
|
+
return false;
|
|
3907
|
+
}
|
|
3908
|
+
const hasRequiredColumns = columns.some((col) => isColumnRequired(col, skipRequired));
|
|
3909
|
+
if (!skipRequired && hasRequiredColumns && activeRows.length === 0) {
|
|
3910
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3911
|
+
dispatch(setError({
|
|
3912
|
+
widgetId,
|
|
3913
|
+
errors: ['Add at least one record and fill all required fields'],
|
|
3914
|
+
}));
|
|
3915
|
+
return false;
|
|
3916
|
+
}
|
|
3917
|
+
activeRows.forEach((row, rowIndex) => {
|
|
3918
|
+
columns.forEach((col) => {
|
|
3919
|
+
if (col['widget-readonly'])
|
|
3920
|
+
return;
|
|
3921
|
+
const key = col['column-key'];
|
|
3922
|
+
if (!key)
|
|
3923
|
+
return;
|
|
3924
|
+
const required = isColumnRequired(col, skipRequired);
|
|
3925
|
+
const cellValue = row[key];
|
|
3926
|
+
const errors = validateWidget(cellValue, col['widget-data-validation'], required, skipRequired);
|
|
3927
|
+
if (errors.length > 0) {
|
|
3928
|
+
isValid = false;
|
|
3929
|
+
const label = col['widget-label'] || key;
|
|
3930
|
+
rowErrors.push(`Row ${rowIndex + 1}, ${label}: ${errors[0]}`);
|
|
3931
|
+
}
|
|
3932
|
+
});
|
|
3933
|
+
});
|
|
3934
|
+
if (!isValid) {
|
|
3935
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3936
|
+
dispatch(setError({
|
|
3937
|
+
widgetId,
|
|
3938
|
+
errors: rowErrors.length > 0
|
|
3939
|
+
? rowErrors.slice(0, 5)
|
|
3940
|
+
: ['Please fix required fields in the table'],
|
|
3941
|
+
}));
|
|
3942
|
+
}
|
|
3943
|
+
else {
|
|
3944
|
+
dispatch(setTouched({ widgetId, touched: false }));
|
|
3945
|
+
dispatch(setError({ widgetId, errors: [] }));
|
|
3946
|
+
}
|
|
3947
|
+
return isValid;
|
|
3948
|
+
};
|
|
3796
3949
|
const collectWidgets = (panels) => {
|
|
3797
3950
|
let widgets = [];
|
|
3798
3951
|
panels.forEach((panel) => {
|
|
@@ -3821,6 +3974,13 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
|
|
|
3821
3974
|
if (!isVisible)
|
|
3822
3975
|
continue;
|
|
3823
3976
|
const widgetId = widget['widget-id'];
|
|
3977
|
+
if (isTableLikeWidget(widget)) {
|
|
3978
|
+
const tableValid = validateTableLikeWidget(widget, currentSchemaData, dispatch, skipRequired);
|
|
3979
|
+
if (!tableValid) {
|
|
3980
|
+
isValid = false;
|
|
3981
|
+
}
|
|
3982
|
+
continue;
|
|
3983
|
+
}
|
|
3824
3984
|
const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
|
|
3825
3985
|
const errors = validateWidget(value, widget['widget-data-validation'], widget['widget-required'], skipRequired);
|
|
3826
3986
|
if (errors.length > 0) {
|
|
@@ -3855,52 +4015,6 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
|
|
|
3855
4015
|
return isValid;
|
|
3856
4016
|
};
|
|
3857
4017
|
|
|
3858
|
-
/** Table-style widgets that bind to an array path in the store / schema. */
|
|
3859
|
-
function isTableLikeWidget(widget) {
|
|
3860
|
-
const w = widget.widget;
|
|
3861
|
-
/** widget-type union in types omits legacy values like simple-table still used at runtime */
|
|
3862
|
-
const t = widget['widget-type'];
|
|
3863
|
-
return (w === 'table' ||
|
|
3864
|
-
w === 'dialog-table' ||
|
|
3865
|
-
w === 'simple-table' ||
|
|
3866
|
-
t === 'table' ||
|
|
3867
|
-
t === 'simple-table');
|
|
3868
|
-
}
|
|
3869
|
-
/**
|
|
3870
|
-
* Resolve `records` for section save payloads.
|
|
3871
|
-
* - Back-compat: path ending in `.records` (e.g. `regId.records`)
|
|
3872
|
-
* - Else: first array snapshot at a string `widget-data-path` on a table-like widget
|
|
3873
|
-
* (e.g. `household.members` for dialog-table)
|
|
3874
|
-
*/
|
|
3875
|
-
function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
|
|
3876
|
-
const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
|
|
3877
|
-
if (convention) {
|
|
3878
|
-
return convention[1];
|
|
3879
|
-
}
|
|
3880
|
-
const tablePaths = [];
|
|
3881
|
-
sectionWidgets.forEach((widget) => {
|
|
3882
|
-
if (!isTableLikeWidget(widget))
|
|
3883
|
-
return;
|
|
3884
|
-
const p = widget['widget-data-path'];
|
|
3885
|
-
if (typeof p === 'string' && p.length > 0) {
|
|
3886
|
-
tablePaths.push(p);
|
|
3887
|
-
}
|
|
3888
|
-
else if (p && typeof p === 'object') {
|
|
3889
|
-
Object.values(p).forEach((sub) => {
|
|
3890
|
-
if (typeof sub === 'string' && sub.length > 0)
|
|
3891
|
-
tablePaths.push(sub);
|
|
3892
|
-
});
|
|
3893
|
-
}
|
|
3894
|
-
});
|
|
3895
|
-
for (const path of tablePaths) {
|
|
3896
|
-
const val = snapshot[path];
|
|
3897
|
-
if (Array.isArray(val)) {
|
|
3898
|
-
return val;
|
|
3899
|
-
}
|
|
3900
|
-
}
|
|
3901
|
-
return [];
|
|
3902
|
-
}
|
|
3903
|
-
|
|
3904
4018
|
/** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
|
|
3905
4019
|
const READONLY_VALUE_ROW_ROOT_CLASSES = [
|
|
3906
4020
|
'TextDisplayWidget',
|
|
@@ -7347,7 +7461,18 @@ const TextInputWidget = ({ config }) => {
|
|
|
7347
7461
|
};
|
|
7348
7462
|
|
|
7349
7463
|
const NumberInputWidget = ({ config }) => {
|
|
7350
|
-
const
|
|
7464
|
+
const resolvedConfig = useMemo(() => {
|
|
7465
|
+
const rawDefault = config['widget-data-default'];
|
|
7466
|
+
if (rawDefault === undefined) {
|
|
7467
|
+
return config;
|
|
7468
|
+
}
|
|
7469
|
+
const normalizedDefault = normalizeNumericDefault(rawDefault, config['widget-data-format']);
|
|
7470
|
+
if (normalizedDefault === undefined || normalizedDefault === rawDefault) {
|
|
7471
|
+
return config;
|
|
7472
|
+
}
|
|
7473
|
+
return { ...config, 'widget-data-default': normalizedDefault };
|
|
7474
|
+
}, [config]);
|
|
7475
|
+
const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
|
|
7351
7476
|
const { translate, translateConfig } = useWidgetTranslation();
|
|
7352
7477
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7353
7478
|
const validationConfig = widgetConfig['widget-data-validation'];
|
|
@@ -7510,6 +7635,8 @@ const BooleanWidget = ({ config }) => {
|
|
|
7510
7635
|
return labels[representation];
|
|
7511
7636
|
}, [representation, formatConfig, translateConfig]);
|
|
7512
7637
|
const { trueLabel, falseLabel } = getLabels();
|
|
7638
|
+
const unsetLabel = useMemo(() => translateConfig(formatConfig?.booleanUnsetLabel || 'Not set'), [formatConfig?.booleanUnsetLabel, translateConfig]);
|
|
7639
|
+
const radioGroupName = `${widgetConfig['widget-id'] ?? 'boolean'}__${useId().replace(/:/g, '')}`;
|
|
7513
7640
|
// Determine current value (handle null/undefined)
|
|
7514
7641
|
const currentValue = useMemo(() => {
|
|
7515
7642
|
if (value === null || value === undefined) {
|
|
@@ -7541,7 +7668,7 @@ const BooleanWidget = ({ config }) => {
|
|
|
7541
7668
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7542
7669
|
let displayValue = '';
|
|
7543
7670
|
if (currentValue === null) {
|
|
7544
|
-
displayValue = '
|
|
7671
|
+
displayValue = '';
|
|
7545
7672
|
}
|
|
7546
7673
|
else if (currentValue === true) {
|
|
7547
7674
|
displayValue = trueLabel;
|
|
@@ -7553,18 +7680,20 @@ const BooleanWidget = ({ config }) => {
|
|
|
7553
7680
|
}
|
|
7554
7681
|
// Render based on control type
|
|
7555
7682
|
if (controlType === 'checkbox') {
|
|
7556
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
7683
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", 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.jsxs("label", { className: "inline-flex items-baseline cursor-pointer gap-2", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: currentValue === true, onChange: handleCheckboxChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), (currentValue === true || currentValue === false) && (jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: currentValue === true ? trueLabel : falseLabel }))] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
7557
7684
|
}
|
|
7558
7685
|
if (controlType === 'radio') {
|
|
7559
7686
|
const containerClass = orientation === 'horizontal'
|
|
7560
|
-
? 'flex flex-row
|
|
7561
|
-
: 'flex flex-col
|
|
7562
|
-
|
|
7687
|
+
? 'flex flex-row flex-wrap items-baseline gap-x-4 gap-y-2'
|
|
7688
|
+
: 'flex flex-col items-start gap-2';
|
|
7689
|
+
const radioDisabled = !isEnabled || widgetConfig['widget-readonly'];
|
|
7690
|
+
const optionDisabledClass = radioDisabled ? 'opacity-50 cursor-not-allowed' : '';
|
|
7691
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", 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.jsxs("div", { className: containerClass, onBlur: onBlur, children: [allowUnset && (jsxRuntimeExports.jsxs("label", { className: `inline-flex items-baseline gap-2 cursor-pointer ${optionDisabledClass}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: radioGroupName, checked: currentValue === null, onChange: () => handleRadioChange(null), disabled: radioDisabled, className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: unsetLabel })] })), jsxRuntimeExports.jsxs("label", { className: `inline-flex items-baseline gap-2 cursor-pointer ${optionDisabledClass}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: radioGroupName, checked: currentValue === true, onChange: () => handleRadioChange(true), disabled: radioDisabled, className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: trueLabel })] }), jsxRuntimeExports.jsxs("label", { className: `inline-flex items-baseline gap-2 cursor-pointer ${optionDisabledClass}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: radioGroupName, checked: currentValue === false, onChange: () => handleRadioChange(false), disabled: radioDisabled, className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: falseLabel })] })] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
7563
7692
|
}
|
|
7564
7693
|
// Toggle/switch control type
|
|
7565
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
7694
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 sm:min-w-[150px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", 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.jsxs("div", { className: "flex flex-wrap items-center gap-3", onBlur: onBlur, children: [allowUnset && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(null), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === null
|
|
7566
7695
|
? 'bg-blue-600 text-white border-blue-600'
|
|
7567
|
-
: 'bg-white text-gray-700 border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`, style: { borderRadius: '15px' }, children:
|
|
7696
|
+
: 'bg-white text-gray-700 border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`, style: { borderRadius: '15px' }, children: unsetLabel })), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(true), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === true
|
|
7568
7697
|
? 'bg-blue-600 text-white border-blue-600'
|
|
7569
7698
|
: 'bg-white text-gray-700 border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`, style: { borderRadius: '15px' }, children: trueLabel }), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(false), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === false
|
|
7570
7699
|
? 'bg-blue-600 text-white border-blue-600'
|
|
@@ -7572,42 +7701,76 @@ const BooleanWidget = ({ config }) => {
|
|
|
7572
7701
|
};
|
|
7573
7702
|
|
|
7574
7703
|
const DateInputWidget = ({ config }) => {
|
|
7575
|
-
const { value,
|
|
7576
|
-
const
|
|
7704
|
+
const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
|
|
7705
|
+
const formValues = useSelector((state) => state.widget.values);
|
|
7706
|
+
const { translateConfig } = useWidgetTranslation();
|
|
7577
7707
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7578
7708
|
const optionsConfig = widgetConfig['widget-data-options'];
|
|
7579
7709
|
const dateFormat = formatConfig?.dateFormat || 'YYYY-MM-DD';
|
|
7580
|
-
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7710
|
+
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7581
7711
|
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
7582
7712
|
const minDate = optionsConfig?.minDate;
|
|
7583
7713
|
const maxDate = optionsConfig?.maxDate;
|
|
7714
|
+
const minDateField = optionsConfig?.minDateField;
|
|
7715
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
7716
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
7717
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
7718
|
+
: undefined;
|
|
7719
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
7720
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
7721
|
+
: undefined;
|
|
7584
7722
|
const defaultToToday = widgetConfig['widget-data-default'] === 'today';
|
|
7585
|
-
// Track manual input value (for manual/hybrid modes)
|
|
7586
7723
|
const [manualInputValue, setManualInputValue] = useState('');
|
|
7587
7724
|
const [isFocused, setIsFocused] = useState(false);
|
|
7588
|
-
|
|
7725
|
+
const fieldMinDate = useMemo(() => {
|
|
7726
|
+
if (!minDateField) {
|
|
7727
|
+
return undefined;
|
|
7728
|
+
}
|
|
7729
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, minDateField));
|
|
7730
|
+
}, [formValues, minDateField]);
|
|
7731
|
+
const fieldMaxDate = useMemo(() => {
|
|
7732
|
+
if (!maxDateField) {
|
|
7733
|
+
return undefined;
|
|
7734
|
+
}
|
|
7735
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, maxDateField));
|
|
7736
|
+
}, [formValues, maxDateField]);
|
|
7737
|
+
const effectiveMinDate = useMemo(() => {
|
|
7738
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
7739
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
7740
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
7741
|
+
const effectiveMaxDate = useMemo(() => {
|
|
7742
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
7743
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
7744
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
7745
|
+
const constraintMessages = useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
7746
|
+
const runDateConstraintValidation = useCallback((dateValue) => {
|
|
7747
|
+
if (!dateValue) {
|
|
7748
|
+
return null;
|
|
7749
|
+
}
|
|
7750
|
+
return validateDateConstraints(dateValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
7751
|
+
}, [effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
7589
7752
|
useEffect(() => {
|
|
7590
7753
|
if (defaultToToday && (value === null || value === undefined || value === '')) {
|
|
7591
7754
|
const todayISO = formatDateToISO(new Date());
|
|
7592
7755
|
onChange(todayISO);
|
|
7593
7756
|
}
|
|
7594
7757
|
}, [defaultToToday, value, onChange]);
|
|
7595
|
-
//
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7758
|
+
// Re-validate when a relative bound field changes (e.g. start date set after end date)
|
|
7759
|
+
useEffect(() => {
|
|
7760
|
+
if (!value) {
|
|
7761
|
+
return;
|
|
7762
|
+
}
|
|
7763
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7764
|
+
if (constraintError) {
|
|
7765
|
+
setError([constraintError]);
|
|
7766
|
+
}
|
|
7767
|
+
}, [fieldMinDate, fieldMaxDate, value, runDateConstraintValidation, setError]);
|
|
7603
7768
|
const getDisplayValue = useCallback(() => {
|
|
7604
|
-
// For picker mode, always use YYYY-MM-DD
|
|
7605
7769
|
if (inputMethod === 'picker') {
|
|
7606
7770
|
if (!value)
|
|
7607
7771
|
return '';
|
|
7608
7772
|
return formatDateToISO(value);
|
|
7609
7773
|
}
|
|
7610
|
-
// For manual/hybrid modes, use custom format
|
|
7611
7774
|
if (isFocused && manualInputValue) {
|
|
7612
7775
|
return manualInputValue;
|
|
7613
7776
|
}
|
|
@@ -7618,7 +7781,6 @@ const DateInputWidget = ({ config }) => {
|
|
|
7618
7781
|
}
|
|
7619
7782
|
return formatDateToString(value, dateFormat);
|
|
7620
7783
|
}, [value, inputMethod, dateFormat, isFocused, manualInputValue]);
|
|
7621
|
-
// Initialize manual input value
|
|
7622
7784
|
useEffect(() => {
|
|
7623
7785
|
if (!isFocused && value) {
|
|
7624
7786
|
if (dateFormat === 'YYYY-MM-DD') {
|
|
@@ -7629,66 +7791,81 @@ const DateInputWidget = ({ config }) => {
|
|
|
7629
7791
|
}
|
|
7630
7792
|
}
|
|
7631
7793
|
}, [value, dateFormat, isFocused]);
|
|
7632
|
-
|
|
7794
|
+
const applyConstraintError = useCallback((dateValue) => {
|
|
7795
|
+
const constraintError = runDateConstraintValidation(dateValue);
|
|
7796
|
+
setError(constraintError ? [constraintError] : []);
|
|
7797
|
+
}, [runDateConstraintValidation, setError]);
|
|
7633
7798
|
const handleChange = useCallback((e) => {
|
|
7634
7799
|
const inputValue = e.target.value;
|
|
7635
7800
|
if (inputMethod === 'picker') {
|
|
7636
|
-
// Picker mode: input is always YYYY-MM-DD
|
|
7637
7801
|
if (inputValue) {
|
|
7638
7802
|
const date = parseDate(inputValue);
|
|
7639
7803
|
if (date) {
|
|
7640
|
-
|
|
7804
|
+
const iso = formatDateToISO(date);
|
|
7805
|
+
onChange(iso);
|
|
7806
|
+
applyConstraintError(iso);
|
|
7641
7807
|
}
|
|
7642
7808
|
else {
|
|
7643
7809
|
onChange('');
|
|
7810
|
+
setError([]);
|
|
7644
7811
|
}
|
|
7645
7812
|
}
|
|
7646
7813
|
else {
|
|
7647
7814
|
onChange('');
|
|
7815
|
+
setError([]);
|
|
7648
7816
|
}
|
|
7649
7817
|
}
|
|
7650
7818
|
else {
|
|
7651
|
-
// Manual/hybrid mode: parse custom format
|
|
7652
7819
|
setManualInputValue(inputValue);
|
|
7653
7820
|
if (inputValue) {
|
|
7654
7821
|
const date = parseDateFromFormat(inputValue, dateFormat);
|
|
7655
7822
|
if (date) {
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
onChange(formatDateToISO(date));
|
|
7660
|
-
}
|
|
7661
|
-
else {
|
|
7662
|
-
// Still update the value but validation will catch it
|
|
7663
|
-
onChange(formatDateToISO(date));
|
|
7664
|
-
}
|
|
7823
|
+
const iso = formatDateToISO(date);
|
|
7824
|
+
onChange(iso);
|
|
7825
|
+
applyConstraintError(iso);
|
|
7665
7826
|
}
|
|
7666
7827
|
}
|
|
7667
7828
|
else {
|
|
7668
7829
|
onChange('');
|
|
7830
|
+
setError([]);
|
|
7669
7831
|
}
|
|
7670
7832
|
}
|
|
7671
|
-
}, [inputMethod, dateFormat, onChange,
|
|
7672
|
-
// Handle blur - validate and format
|
|
7833
|
+
}, [inputMethod, dateFormat, onChange, applyConstraintError, setError]);
|
|
7673
7834
|
const handleBlur = useCallback(() => {
|
|
7674
7835
|
setIsFocused(false);
|
|
7675
7836
|
if (inputMethod !== 'picker' && manualInputValue) {
|
|
7676
7837
|
const date = parseDateFromFormat(manualInputValue, dateFormat);
|
|
7677
7838
|
if (date) {
|
|
7678
|
-
// Format the value according to the format
|
|
7679
7839
|
const formatted = formatDateToString(date, dateFormat);
|
|
7680
7840
|
setManualInputValue(formatted);
|
|
7681
|
-
|
|
7841
|
+
const iso = formatDateToISO(date);
|
|
7842
|
+
onChange(iso);
|
|
7843
|
+
applyConstraintError(iso);
|
|
7682
7844
|
}
|
|
7683
7845
|
else {
|
|
7684
|
-
// Invalid date, clear it
|
|
7685
7846
|
setManualInputValue('');
|
|
7686
7847
|
onChange('');
|
|
7848
|
+
setError([]);
|
|
7687
7849
|
}
|
|
7688
7850
|
}
|
|
7689
7851
|
onBlur();
|
|
7690
|
-
|
|
7691
|
-
|
|
7852
|
+
if (value) {
|
|
7853
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7854
|
+
if (constraintError) {
|
|
7855
|
+
setError([constraintError]);
|
|
7856
|
+
}
|
|
7857
|
+
}
|
|
7858
|
+
}, [
|
|
7859
|
+
inputMethod,
|
|
7860
|
+
manualInputValue,
|
|
7861
|
+
dateFormat,
|
|
7862
|
+
onChange,
|
|
7863
|
+
onBlur,
|
|
7864
|
+
applyConstraintError,
|
|
7865
|
+
value,
|
|
7866
|
+
runDateConstraintValidation,
|
|
7867
|
+
setError,
|
|
7868
|
+
]);
|
|
7692
7869
|
const handleFocus = useCallback(() => {
|
|
7693
7870
|
setIsFocused(true);
|
|
7694
7871
|
if (value) {
|
|
@@ -7700,15 +7877,15 @@ const DateInputWidget = ({ config }) => {
|
|
|
7700
7877
|
}
|
|
7701
7878
|
}
|
|
7702
7879
|
}, [value, dateFormat]);
|
|
7703
|
-
// Determine placeholder
|
|
7704
7880
|
const placeholder = useMemo(() => {
|
|
7705
|
-
const
|
|
7881
|
+
const display = getDisplayValue();
|
|
7882
|
+
const hasValue = display && display.trim().length > 0;
|
|
7706
7883
|
const placeholderText = translateConfig(widgetConfig['widget-data-placeholder']);
|
|
7707
|
-
return hasValue ? undefined :
|
|
7884
|
+
return hasValue ? undefined : placeholderText || dateFormat;
|
|
7708
7885
|
}, [getDisplayValue, widgetConfig, translateConfig, dateFormat]);
|
|
7709
|
-
// Determine input type
|
|
7710
7886
|
const inputType = inputMethod === 'picker' ? 'date' : 'text';
|
|
7711
|
-
|
|
7887
|
+
const showRequiredError = widgetConfig['widget-required'] && (!value || value === '');
|
|
7888
|
+
const showValidationError = touched && error.length > 0;
|
|
7712
7889
|
if (widgetConfig['widget-readonly']) {
|
|
7713
7890
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7714
7891
|
let displayValue = '';
|
|
@@ -7725,9 +7902,9 @@ const DateInputWidget = ({ config }) => {
|
|
|
7725
7902
|
}
|
|
7726
7903
|
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 }) })] }));
|
|
7727
7904
|
}
|
|
7728
|
-
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'] &&
|
|
7905
|
+
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
|
|
7729
7906
|
? 'border-red-500 focus:ring-red-500 focus:border-red-500'
|
|
7730
|
-
: 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }),
|
|
7907
|
+
: '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] })] })] }) }));
|
|
7731
7908
|
};
|
|
7732
7909
|
|
|
7733
7910
|
/**
|
|
@@ -8275,7 +8452,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8275
8452
|
const displayValue = isChecked ? 'Yes' : 'No';
|
|
8276
8453
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] CheckboxDisplayWidget 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 }) })] }));
|
|
8277
8454
|
}
|
|
8278
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
8455
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", 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.jsxs("label", { className: "inline-flex cursor-pointer items-baseline gap-2", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => onChange(e.target.checked), onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-base leading-normal text-gray-700", children: isChecked ? 'Yes' : 'No' })] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
8279
8456
|
}
|
|
8280
8457
|
// Multiple checkboxes (with data source) - for array values
|
|
8281
8458
|
// Process and sort options if needed
|
|
@@ -8318,7 +8495,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8318
8495
|
switch (layout) {
|
|
8319
8496
|
case 'horizontal':
|
|
8320
8497
|
return {
|
|
8321
|
-
className: 'flex flex-row flex-wrap gap-4',
|
|
8498
|
+
className: 'flex flex-row flex-wrap items-baseline gap-4',
|
|
8322
8499
|
style: undefined,
|
|
8323
8500
|
};
|
|
8324
8501
|
case 'grid':
|
|
@@ -8331,7 +8508,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8331
8508
|
case 'vertical':
|
|
8332
8509
|
default:
|
|
8333
8510
|
return {
|
|
8334
|
-
className: 'flex flex-col
|
|
8511
|
+
className: 'flex flex-col gap-2',
|
|
8335
8512
|
style: undefined,
|
|
8336
8513
|
};
|
|
8337
8514
|
}
|
|
@@ -8345,7 +8522,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8345
8522
|
: '-';
|
|
8346
8523
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-3 CheckboxDisplayWidget flex flex-col sm:flex-row sm:items-start", children: [label && (jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", 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 }) })] }));
|
|
8347
8524
|
}
|
|
8348
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
8525
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", 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("div", { className: layoutConfig.className, style: layoutConfig.style, onBlur: onBlur, children: loading ? (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500", children: translate('common.loading') })) : (processedOptions.map((option) => (jsxRuntimeExports.jsxs("label", { className: `inline-flex cursor-pointer items-baseline gap-2 ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : ''}`, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", value: option.value, checked: selectedValues.includes(option.value), onChange: (e) => handleCheckboxChange(option.value, e.target.checked), disabled: !isEnabled || widgetConfig['widget-readonly'], className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-base leading-normal text-gray-700", children: translateConfig(option.label) })] }, option.value)))) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
8349
8526
|
};
|
|
8350
8527
|
|
|
8351
8528
|
const SimpleTableWidget = ({ config }) => {
|
|
@@ -8671,16 +8848,70 @@ const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
|
8671
8848
|
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8672
8849
|
} }));
|
|
8673
8850
|
};
|
|
8674
|
-
const TableCellDate = ({ config, value, onValueChange }) => {
|
|
8851
|
+
const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
8852
|
+
const { translateConfig } = useWidgetTranslation();
|
|
8675
8853
|
const isReadonly = config['widget-readonly'] || false;
|
|
8676
8854
|
const placeholder = config['widget-data-placeholder'] || '';
|
|
8855
|
+
const optionsConfig = config['widget-data-options'];
|
|
8856
|
+
const formatConfig = config['widget-data-format'];
|
|
8857
|
+
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
8858
|
+
const minDate = optionsConfig?.minDate;
|
|
8859
|
+
const maxDate = optionsConfig?.maxDate;
|
|
8860
|
+
const minDateField = optionsConfig?.minDateField;
|
|
8861
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
8862
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
8863
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
8864
|
+
: undefined;
|
|
8865
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
8866
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
8867
|
+
: undefined;
|
|
8868
|
+
const [constraintError, setConstraintError] = useState(null);
|
|
8869
|
+
const resolveSiblingDate = (fieldRef) => {
|
|
8870
|
+
if (!fieldRef || !rowValues) {
|
|
8871
|
+
return undefined;
|
|
8872
|
+
}
|
|
8873
|
+
const raw = getValueByPath(rowValues, fieldRef) ?? rowValues[fieldRef];
|
|
8874
|
+
return resolveDateBoundFromFieldValue(raw);
|
|
8875
|
+
};
|
|
8876
|
+
const fieldMinDate = useMemo(() => resolveSiblingDate(minDateField), [minDateField, rowValues]);
|
|
8877
|
+
const fieldMaxDate = useMemo(() => resolveSiblingDate(maxDateField), [maxDateField, rowValues]);
|
|
8878
|
+
const effectiveMinDate = useMemo(() => {
|
|
8879
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
8880
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
8881
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
8882
|
+
const effectiveMaxDate = useMemo(() => {
|
|
8883
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
8884
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
8885
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
8886
|
+
const constraintMessages = useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
8677
8887
|
// input type="date" requires YYYY-MM-DD format
|
|
8678
8888
|
const displayValue = value && typeof value === 'string' ? value.split('T')[0] : '';
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
}
|
|
8889
|
+
useEffect(() => {
|
|
8890
|
+
if (!displayValue) {
|
|
8891
|
+
setConstraintError(null);
|
|
8892
|
+
return;
|
|
8893
|
+
}
|
|
8894
|
+
const error = validateDateConstraints(displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8895
|
+
setConstraintError(error);
|
|
8896
|
+
}, [displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
8897
|
+
const handleChange = (e) => {
|
|
8898
|
+
const nextValue = e.target.value;
|
|
8899
|
+
onValueChange(nextValue);
|
|
8900
|
+
if (!nextValue) {
|
|
8901
|
+
setConstraintError(null);
|
|
8902
|
+
return;
|
|
8903
|
+
}
|
|
8904
|
+
const error = validateDateConstraints(nextValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8905
|
+
setConstraintError(error);
|
|
8906
|
+
};
|
|
8907
|
+
const hasError = Boolean(constraintError);
|
|
8908
|
+
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: {
|
|
8909
|
+
borderRadius: '10px',
|
|
8910
|
+
borderColor: hasError
|
|
8911
|
+
? 'var(--owt-color-error, #B91C1C)'
|
|
8912
|
+
: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8913
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8914
|
+
} }), hasError && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-xs mt-0.5 leading-tight", children: constraintError }))] }));
|
|
8684
8915
|
};
|
|
8685
8916
|
const TableWidget = ({ config }) => {
|
|
8686
8917
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
|
|
@@ -9039,11 +9270,21 @@ const TableWidget = ({ config }) => {
|
|
|
9039
9270
|
});
|
|
9040
9271
|
}
|
|
9041
9272
|
}, [isAdding, newRowData, columns, widgetConfig, rows.length, dispatch]);
|
|
9273
|
+
const getRowValuesForEdit = useCallback((rowIndex) => {
|
|
9274
|
+
if (editingState && editingState.rowIndex === rowIndex) {
|
|
9275
|
+
return editingState.currentValue ?? {};
|
|
9276
|
+
}
|
|
9277
|
+
if (isAdding && rowIndex === rows.length && newRowData) {
|
|
9278
|
+
return newRowData;
|
|
9279
|
+
}
|
|
9280
|
+
return rows[rowIndex] ?? {};
|
|
9281
|
+
}, [editingState, isAdding, rows, newRowData]);
|
|
9042
9282
|
// Lightweight cell renderer for table cells (no labels, compact)
|
|
9043
9283
|
const renderTableCell = useCallback((rowIndex, column, cellValue, isReadonly) => {
|
|
9044
9284
|
const columnKey = column['column-key'];
|
|
9045
9285
|
const widgetType = column.widget || 'text';
|
|
9046
9286
|
const cellWidgetId = `${widgetConfig['widget-id']}-row-${rowIndex}-col-${columnKey}`;
|
|
9287
|
+
const rowValues = getRowValuesForEdit(rowIndex);
|
|
9047
9288
|
// Use lightweight cell config (no label, minimal styling)
|
|
9048
9289
|
const cellConfig = {
|
|
9049
9290
|
...column,
|
|
@@ -9066,7 +9307,7 @@ const TableWidget = ({ config }) => {
|
|
|
9066
9307
|
return jsxRuntimeExports.jsx(TableCellNumber, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9067
9308
|
}
|
|
9068
9309
|
else if (widgetType === 'date') {
|
|
9069
|
-
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9310
|
+
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, rowValues: rowValues, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9070
9311
|
}
|
|
9071
9312
|
// For other widget types, use WidgetRenderer but with compact styling
|
|
9072
9313
|
return (jsxRuntimeExports.jsx("div", { className: "table-cell-widget", style: { margin: 0, padding: 0 }, children: jsxRuntimeExports.jsx(WidgetRenderer, { config: cellConfig, schemaData: {
|
|
@@ -9074,7 +9315,7 @@ const TableWidget = ({ config }) => {
|
|
|
9074
9315
|
}, onValueChange: (widgetId, newValue) => {
|
|
9075
9316
|
updateCellValue(columnKey, newValue, rowIndex);
|
|
9076
9317
|
} }) }));
|
|
9077
|
-
}, [widgetConfig, updateCellValue]);
|
|
9318
|
+
}, [widgetConfig, updateCellValue, getRowValuesForEdit]);
|
|
9078
9319
|
// Render cell content (widget in edit mode, formatted value in view mode)
|
|
9079
9320
|
const renderCell = useCallback((rowIndex, column, row) => {
|
|
9080
9321
|
const columnKey = column['column-key'];
|
|
@@ -9384,6 +9625,27 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9384
9625
|
}, [formData, columns, storeValues, dialogFieldWidgetId]);
|
|
9385
9626
|
const saveDialog = useCallback(() => {
|
|
9386
9627
|
const payload = collectMergedRowPayload();
|
|
9628
|
+
let hasErrors = false;
|
|
9629
|
+
columns.forEach((col) => {
|
|
9630
|
+
const key = col['column-key'];
|
|
9631
|
+
const cellWidgetId = dialogFieldWidgetId(key);
|
|
9632
|
+
const isColReadonly = isReadonly || col['widget-readonly'] === true;
|
|
9633
|
+
if (isColReadonly)
|
|
9634
|
+
return;
|
|
9635
|
+
const cellValue = payload[key];
|
|
9636
|
+
const validationErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
|
|
9637
|
+
if (validationErrors && validationErrors.length > 0) {
|
|
9638
|
+
hasErrors = true;
|
|
9639
|
+
dispatch(setError({ widgetId: cellWidgetId, errors: validationErrors }));
|
|
9640
|
+
dispatch(setTouched({ widgetId: cellWidgetId, touched: true }));
|
|
9641
|
+
}
|
|
9642
|
+
else {
|
|
9643
|
+
dispatch(setError({ widgetId: cellWidgetId, errors: [] }));
|
|
9644
|
+
}
|
|
9645
|
+
});
|
|
9646
|
+
if (hasErrors) {
|
|
9647
|
+
return;
|
|
9648
|
+
}
|
|
9387
9649
|
if (dialogMode === 'add') {
|
|
9388
9650
|
const savedRow = { ...payload, edit_action: 'ADD' };
|
|
9389
9651
|
onChange([...rows, savedRow]);
|
|
@@ -9399,7 +9661,7 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9399
9661
|
onChange(newRows);
|
|
9400
9662
|
closeDialog();
|
|
9401
9663
|
}
|
|
9402
|
-
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex]);
|
|
9664
|
+
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
|
|
9403
9665
|
const deleteRow = useCallback((rowIndex) => {
|
|
9404
9666
|
const newRows = rows.filter((_, i) => i !== rowIndex);
|
|
9405
9667
|
onChange(newRows);
|
|
@@ -10225,20 +10487,29 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10225
10487
|
.${cls} .hdr-field-row {
|
|
10226
10488
|
display: flex;
|
|
10227
10489
|
align-items: flex-start;
|
|
10228
|
-
gap: 0.5rem;
|
|
10229
10490
|
font-size: 1rem;
|
|
10230
10491
|
line-height: 1.6;
|
|
10231
10492
|
}
|
|
10232
10493
|
|
|
10233
10494
|
.${cls} .hdr-field-label {
|
|
10495
|
+
width: 50%;
|
|
10496
|
+
flex: 0 0 50%;
|
|
10234
10497
|
color: rgba(0, 0, 0, 0.5);
|
|
10235
10498
|
font-weight: 400;
|
|
10236
10499
|
white-space: nowrap;
|
|
10500
|
+
overflow: hidden;
|
|
10501
|
+
text-overflow: ellipsis;
|
|
10502
|
+
padding-right: 4px;
|
|
10237
10503
|
}
|
|
10238
10504
|
|
|
10239
10505
|
.${cls} .hdr-field-value {
|
|
10506
|
+
width: 50%;
|
|
10507
|
+
flex: 0 0 50%;
|
|
10240
10508
|
color: var(--owt-color-text, #111827);
|
|
10241
10509
|
font-weight: 500;
|
|
10510
|
+
white-space: nowrap;
|
|
10511
|
+
overflow: hidden;
|
|
10512
|
+
text-overflow: ellipsis;
|
|
10242
10513
|
}
|
|
10243
10514
|
|
|
10244
10515
|
.${cls} .hdr-status-badge {
|
|
@@ -10248,24 +10519,38 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10248
10519
|
font-size: 0.75rem;
|
|
10249
10520
|
font-weight: 600;
|
|
10250
10521
|
color: #fff;
|
|
10522
|
+
max-width: 100%;
|
|
10523
|
+
overflow: hidden;
|
|
10524
|
+
text-overflow: ellipsis;
|
|
10525
|
+
white-space: nowrap;
|
|
10251
10526
|
}
|
|
10252
10527
|
|
|
10253
10528
|
.${cls} .hdr-meta-row {
|
|
10254
10529
|
display: flex;
|
|
10255
10530
|
align-items: baseline;
|
|
10256
|
-
gap: 0.35rem;
|
|
10257
10531
|
font-size: 1rem;
|
|
10258
10532
|
line-height: 1.6;
|
|
10259
10533
|
}
|
|
10260
10534
|
|
|
10261
10535
|
.${cls} .hdr-meta-label {
|
|
10536
|
+
width: 50%;
|
|
10537
|
+
flex: 0 0 50%;
|
|
10262
10538
|
color: rgba(0, 0, 0, 0.5);
|
|
10263
10539
|
font-weight: 400;
|
|
10540
|
+
white-space: nowrap;
|
|
10541
|
+
overflow: hidden;
|
|
10542
|
+
text-overflow: ellipsis;
|
|
10543
|
+
padding-right: 4px;
|
|
10264
10544
|
}
|
|
10265
10545
|
|
|
10266
10546
|
.${cls} .hdr-meta-value {
|
|
10547
|
+
width: 50%;
|
|
10548
|
+
flex: 0 0 50%;
|
|
10267
10549
|
color: var(--owt-color-text, #111827);
|
|
10268
10550
|
font-weight: 500;
|
|
10551
|
+
white-space: nowrap;
|
|
10552
|
+
overflow: hidden;
|
|
10553
|
+
text-overflow: ellipsis;
|
|
10269
10554
|
}
|
|
10270
10555
|
|
|
10271
10556
|
.${cls} .hdr-select {
|
|
@@ -10329,7 +10614,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10329
10614
|
.parentElement?.querySelector('.hdr-avatar-placeholder');
|
|
10330
10615
|
if (placeholder)
|
|
10331
10616
|
placeholder.style.display = 'flex';
|
|
10332
|
-
} })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: displayImageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) }), !isReadonly && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "hdr-avatar-overlay", children: [jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action", onClick: () => fileInputRef.current?.click(), children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), jsxRuntimeExports.jsx("polyline", { points: "17 8 12 3 7 8" }), jsxRuntimeExports.jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })] }), "Upload"] }), jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action hdr-avatar-action--delete", onClick: handleImageDelete, children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("polyline", { points: "3 6 5 6 21 6" }), jsxRuntimeExports.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })] }), "Delete"] })] }), jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: handleImageUpload })] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('functionalId'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: functionalId || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx("span", { className: "hdr-field-label", children: getLabel('status') }), isReadonly ? (statusLabel ? (jsxRuntimeExports.jsx("span", { className: "hdr-status-badge", style: { backgroundColor: statusColor }, children: statusLabel })) : (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: "-" }))) : (jsxRuntimeExports.jsxs("select", { className: "hdr-select", value: statusValue, onChange: (e) => updateFieldValue('status', e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: getLabel('select') }), statusOptions.map((opt) => (jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('statusReason'), " :"] }), isReadonly ? (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: statusReason || '-' })) : (jsxRuntimeExports.jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [jsxRuntimeExports.jsx("input", { type: "text", className: `hdr-input ${(!isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing) ? 'hdr-input--error' : ''}`, value: statusReason, placeholder: getLabel('enterReason'), required: isStatusChanged, "aria-required": isStatusChanged, "aria-invalid": !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing, onBlur: () => {
|
|
10617
|
+
} })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: displayImageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) }), !isReadonly && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "hdr-avatar-overlay", children: [jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action", onClick: () => fileInputRef.current?.click(), children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), jsxRuntimeExports.jsx("polyline", { points: "17 8 12 3 7 8" }), jsxRuntimeExports.jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })] }), "Upload"] }), jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action hdr-avatar-action--delete", onClick: handleImageDelete, children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("polyline", { points: "3 6 5 6 21 6" }), jsxRuntimeExports.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })] }), "Delete"] })] }), jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: handleImageUpload })] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", title: `${getLabel('functionalId')} :`, children: [getLabel('functionalId'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-field-value", title: functionalId || '-', children: functionalId || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx("span", { className: "hdr-field-label", title: getLabel('status'), children: getLabel('status') }), isReadonly ? (statusLabel ? (jsxRuntimeExports.jsx("span", { className: "hdr-status-badge", style: { backgroundColor: statusColor }, title: statusLabel, children: statusLabel })) : (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", title: "-", children: "-" }))) : (jsxRuntimeExports.jsxs("select", { className: "hdr-select", value: statusValue, onChange: (e) => updateFieldValue('status', e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: getLabel('select') }), statusOptions.map((opt) => (jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", title: `${getLabel('statusReason')} :`, children: [getLabel('statusReason'), " :"] }), isReadonly ? (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", title: statusReason || '-', children: statusReason || '-' })) : (jsxRuntimeExports.jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [jsxRuntimeExports.jsx("input", { type: "text", className: `hdr-input ${(!isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing) ? 'hdr-input--error' : ''}`, value: statusReason, placeholder: getLabel('enterReason'), required: isStatusChanged, "aria-required": isStatusChanged, "aria-invalid": !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing, onBlur: () => {
|
|
10333
10618
|
if (isReasonMissing)
|
|
10334
10619
|
setShowReasonRequired(true);
|
|
10335
10620
|
}, onChange: (e) => {
|
|
@@ -10337,7 +10622,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10337
10622
|
if (showReasonRequired && String(e.target.value || '').trim().length > 0) {
|
|
10338
10623
|
setShowReasonRequired(false);
|
|
10339
10624
|
}
|
|
10340
|
-
} }), !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing ? (jsxRuntimeExports.jsx("div", { className: "hdr-error-text", children: getLabel('enterReason') })) : null] }))] })] })] }), jsxRuntimeExports.jsx("div", { className: "hdr-right", children: jsxRuntimeExports.jsxs("div", { className: "hdr-right-top", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-col", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdAt || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedAt || '-' })] })] }), score ? (jsxRuntimeExports.jsx("div", { className: "hdr-score-ring", style: { ['--pct']: score.percent }, "aria-label": `Completion score ${score.completionDisplay} of ${score.idealDisplay} (${score.percent}%)`, title: `${score.completionDisplay} / ${score.idealDisplay} (${score.percent}%)`, children: jsxRuntimeExports.jsx("div", { className: "hdr-score-value", children: String(score.completionDisplay) }) })) : null] }) })] })] }));
|
|
10625
|
+
} }), !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing ? (jsxRuntimeExports.jsx("div", { className: "hdr-error-text", children: getLabel('enterReason') })) : null] }))] })] })] }), jsxRuntimeExports.jsx("div", { className: "hdr-right", children: jsxRuntimeExports.jsxs("div", { className: "hdr-right-top", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-col", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('createdBy')} :`, children: [getLabel('createdBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: createdBy || '-', children: createdBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('createdAt')} :`, children: [getLabel('createdAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: createdAt || '-', children: createdAt || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('lastApprovedBy')} :`, children: [getLabel('lastApprovedBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: lastApprovedBy || '-', children: lastApprovedBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('lastApprovedAt')} :`, children: [getLabel('lastApprovedAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: lastApprovedAt || '-', children: lastApprovedAt || '-' })] })] }), score ? (jsxRuntimeExports.jsx("div", { className: "hdr-score-ring", style: { ['--pct']: score.percent }, "aria-label": `Completion score ${score.completionDisplay} of ${score.idealDisplay} (${score.percent}%)`, title: `${score.completionDisplay} / ${score.idealDisplay} (${score.percent}%)`, children: jsxRuntimeExports.jsx("div", { className: "hdr-score-value", children: String(score.completionDisplay) }) })) : null] }) })] })] }));
|
|
10341
10626
|
};
|
|
10342
10627
|
|
|
10343
10628
|
function getValueByPathOrKey(obj, path) {
|
|
@@ -11482,5 +11767,5 @@ const translateUISchema = (schema, translate) => {
|
|
|
11482
11767
|
};
|
|
11483
11768
|
};
|
|
11484
11769
|
|
|
11485
|
-
export { ArrayWidget, BooleanWidget, CheckboxWidget, CurrencyInputWidget, DateInputWidget, DateTimeInputWidget, DialogTableWidget, DisplayWidget, FileInputWidget, HeaderSectionWidget, IdAuthenticationWidget, IterableAccordionWidget, JSONEditorPanel, NumberInputWidget, PanelRenderer, PhoneInputWidget, ProfileWidget, PropertyEditor, RadioWidget, ScoresDisplayWidget, SectionBuilder, SectionRenderer, SectionTree, SectionsContainer, SelectWidget, SimpleTableWidget, TableWidget, TextAreaWidget, TextInputWidget, VisualBuilderPanel, WidgetEventBus, WidgetProvider, WidgetRenderer, applyCaseControl, applyDecimalPrecision, applyMask, createWidgetStore, createZodSchema, defaultTheme, evaluateCondition, filterByCharacterType, formatCurrency, formatDate, formatNumber, formatPhone, formatValue, geoHierarchyBuilder, getApiDataSource, getFormattedNumberLength, getSchemaDataSource, getStaticDataSource, getValueByPath, getWidgetValue, initI18n, isAllowedKey, parseDataPath, parseNumber, registerDefaultWidgets, removeMask, resetAll, resetWidget, resolveTheme, setDataSource, setError, setLoading, setTouched, setValue, setValueByPath, setValues, setWidgetValue, shouldEnableWidget, shouldShowWidget, transformDataSourceOptions, translatePanelConfig, translateUISchema, translateWidgetConfig, useBaseWidget, useGeoWidgetCascade, useWidgetCascade, useWidgetContext, useWidgetEventBus, useWidgetTheme, useWidgetTranslation, validateNumericValue, validateWidget, widgetRegistry };
|
|
11770
|
+
export { ArrayWidget, BooleanWidget, CheckboxWidget, CurrencyInputWidget, DateInputWidget, DateTimeInputWidget, DialogTableWidget, DisplayWidget, FileInputWidget, HeaderSectionWidget, IdAuthenticationWidget, IterableAccordionWidget, JSONEditorPanel, NumberInputWidget, PanelRenderer, PhoneInputWidget, ProfileWidget, PropertyEditor, RadioWidget, ScoresDisplayWidget, SectionBuilder, SectionRenderer, SectionTree, SectionsContainer, SelectWidget, SimpleTableWidget, TableWidget, TextAreaWidget, TextInputWidget, VisualBuilderPanel, WidgetEventBus, WidgetProvider, WidgetRenderer, applyCaseControl, applyDecimalPrecision, applyMask, createWidgetStore, createZodSchema, defaultTheme, evaluateCondition, filterByCharacterType, formatCurrency, formatDate, formatNumber, formatPhone, formatValue, geoHierarchyBuilder, getApiDataSource, getFormattedNumberLength, getSchemaDataSource, getStaticDataSource, getValueByPath, getWidgetValue, initI18n, isAllowedKey, normalizeNumericDefault, parseDataPath, parseNumber, registerDefaultWidgets, removeMask, resetAll, resetWidget, resolveTheme, setDataSource, setError, setLoading, setTouched, setValue, setValueByPath, setValues, setWidgetValue, shouldEnableWidget, shouldShowWidget, transformDataSourceOptions, translatePanelConfig, translateUISchema, translateWidgetConfig, useBaseWidget, useGeoWidgetCascade, useWidgetCascade, useWidgetContext, useWidgetEventBus, useWidgetTheme, useWidgetTranslation, validateNumericValue, validateWidget, widgetRegistry };
|
|
11486
11771
|
//# sourceMappingURL=index.esm.js.map
|