@openg2p/registry-widgets 1.1.0-dev.12 → 1.1.0-dev.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1078,16 +1078,12 @@ const getApiDataSource = async (dataSource, allValues, dataSourceRequestHandler,
1078
1078
  console.error('[getApiDataSource] API data source missing endpoint. Use "endpoint" field to specify the operation (e.g., "get_g2p_geo_level_values")');
1079
1079
  return [];
1080
1080
  }
1081
- let response;
1082
- try {
1083
- response = await dataSourceRequestHandler(service, endpoint, method, requestParams, {
1084
- headers: dataSource.headers,
1085
- });
1086
- }
1087
- catch (error) {
1088
- console.error('[getApiDataSource] Handler error:', error);
1089
- throw error;
1090
- }
1081
+ // Call handler — let any throw propagate to the outer catch so it is logged once
1082
+ // by useBaseWidget rather than double-logged here (which can cascade when
1083
+ // intercept-console-error.js converts console.error calls into thrown errors).
1084
+ const response = await dataSourceRequestHandler(service, endpoint, method, requestParams, {
1085
+ headers: dataSource.headers,
1086
+ });
1091
1087
  // Handle OpenG2P response format (response_body.response_payload)
1092
1088
  if (response && typeof response === 'object') {
1093
1089
  if (response.response_body?.response_payload && Array.isArray(response.response_body.response_payload)) {
@@ -1110,8 +1106,8 @@ const getApiDataSource = async (dataSource, allValues, dataSourceRequestHandler,
1110
1106
  return [];
1111
1107
  }
1112
1108
  catch (error) {
1113
- console.error('Error fetching API data source:', error);
1114
- return [];
1109
+ // Rethrow so useBaseWidget's catch can log it with full widget context
1110
+ throw error;
1115
1111
  }
1116
1112
  };
1117
1113
  /**
@@ -2305,7 +2301,7 @@ const useBaseWidget = (options) => {
2305
2301
  dispatch(setDataSource({ widgetId, data: transformed }));
2306
2302
  }
2307
2303
  catch (error) {
2308
- console.error(`[useBaseWidget] ERROR loading data source for ${widgetId}:`, error);
2304
+ console.error(`[useBaseWidget] ERROR loading data source for widget "${widgetId}" (type="${dataSource.type}"):`, error, '\nWidget config:', config, '\ndataSourceRequestHandler provided:', Boolean(dataSourceRequestHandler));
2309
2305
  dispatch(setDataSource({ widgetId, data: [] }));
2310
2306
  }
2311
2307
  finally {
@@ -3798,6 +3794,116 @@ const namespaceSectionConfig = (section, namespace) => {
3798
3794
  return namespaced;
3799
3795
  };
3800
3796
 
3797
+ /** Table-style widgets that bind to an array path in the store / schema. */
3798
+ function isTableLikeWidget(widget) {
3799
+ const w = widget.widget;
3800
+ /** widget-type union in types omits legacy values like simple-table still used at runtime */
3801
+ const t = widget['widget-type'];
3802
+ return (w === 'table' ||
3803
+ w === 'dialog-table' ||
3804
+ w === 'simple-table' ||
3805
+ t === 'table' ||
3806
+ t === 'simple-table');
3807
+ }
3808
+ /**
3809
+ * Resolve `records` for section save payloads.
3810
+ * - Back-compat: path ending in `.records` (e.g. `regId.records`)
3811
+ * - Else: first array snapshot at a string `widget-data-path` on a table-like widget
3812
+ * (e.g. `household.members` for dialog-table)
3813
+ */
3814
+ function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
3815
+ const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
3816
+ if (convention) {
3817
+ return convention[1];
3818
+ }
3819
+ const tablePaths = [];
3820
+ sectionWidgets.forEach((widget) => {
3821
+ if (!isTableLikeWidget(widget))
3822
+ return;
3823
+ const p = widget['widget-data-path'];
3824
+ if (typeof p === 'string' && p.length > 0) {
3825
+ tablePaths.push(p);
3826
+ }
3827
+ else if (p && typeof p === 'object') {
3828
+ Object.values(p).forEach((sub) => {
3829
+ if (typeof sub === 'string' && sub.length > 0)
3830
+ tablePaths.push(sub);
3831
+ });
3832
+ }
3833
+ });
3834
+ for (const path of tablePaths) {
3835
+ const val = snapshot[path];
3836
+ if (Array.isArray(val)) {
3837
+ return val;
3838
+ }
3839
+ }
3840
+ return [];
3841
+ }
3842
+
3843
+ const isColumnRequired = (column, skipRequired) => {
3844
+ if (skipRequired)
3845
+ return false;
3846
+ const validation = column['widget-data-validation'];
3847
+ return !!(column['widget-required'] || validation?.required);
3848
+ };
3849
+ const validateTableLikeWidget = (widget, currentSchemaData, dispatch, skipRequired) => {
3850
+ const widgetId = widget['widget-id'];
3851
+ if (!widgetId)
3852
+ return true;
3853
+ const columns = (widget['widget-data-columns'] || []);
3854
+ const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
3855
+ const rows = Array.isArray(value)
3856
+ ? value
3857
+ : [];
3858
+ const activeRows = rows.filter((row) => row?.edit_action !== 'DELETE');
3859
+ const rowErrors = [];
3860
+ let isValid = true;
3861
+ if (!skipRequired && widget['widget-required'] && activeRows.length === 0) {
3862
+ dispatch(setTouched({ widgetId, touched: true }));
3863
+ dispatch(setError({ widgetId, errors: ['At least one record is required'] }));
3864
+ return false;
3865
+ }
3866
+ const hasRequiredColumns = columns.some((col) => isColumnRequired(col, skipRequired));
3867
+ if (!skipRequired && hasRequiredColumns && activeRows.length === 0) {
3868
+ dispatch(setTouched({ widgetId, touched: true }));
3869
+ dispatch(setError({
3870
+ widgetId,
3871
+ errors: ['Add at least one record and fill all required fields'],
3872
+ }));
3873
+ return false;
3874
+ }
3875
+ activeRows.forEach((row, rowIndex) => {
3876
+ columns.forEach((col) => {
3877
+ if (col['widget-readonly'])
3878
+ return;
3879
+ const key = col['column-key'];
3880
+ if (!key)
3881
+ return;
3882
+ const required = isColumnRequired(col, skipRequired);
3883
+ const cellValue = row[key];
3884
+ const errors = validateWidget(cellValue, col['widget-data-validation'], required, skipRequired);
3885
+ if (errors.length > 0) {
3886
+ isValid = false;
3887
+ const label = col['widget-label'] || key;
3888
+ rowErrors.push(`Row ${rowIndex + 1}, ${label}: ${errors[0]}`);
3889
+ }
3890
+ });
3891
+ });
3892
+ if (!isValid) {
3893
+ dispatch(setTouched({ widgetId, touched: true }));
3894
+ dispatch(setError({
3895
+ widgetId,
3896
+ errors: rowErrors.length > 0
3897
+ ? rowErrors.slice(0, 5)
3898
+ : ['Please fix required fields in the table'],
3899
+ }));
3900
+ }
3901
+ else {
3902
+ dispatch(setTouched({ widgetId, touched: false }));
3903
+ dispatch(setError({ widgetId, errors: [] }));
3904
+ }
3905
+ return isValid;
3906
+ };
3801
3907
  const collectWidgets = (panels) => {
3802
3908
  let widgets = [];
3803
3909
  panels.forEach((panel) => {
@@ -3826,6 +3932,13 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
3826
3932
  if (!isVisible)
3827
3933
  continue;
3828
3934
  const widgetId = widget['widget-id'];
3935
+ if (isTableLikeWidget(widget)) {
3936
+ const tableValid = validateTableLikeWidget(widget, currentSchemaData, dispatch, skipRequired);
3937
+ if (!tableValid) {
3938
+ isValid = false;
3939
+ }
3940
+ continue;
3941
+ }
3829
3942
  const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
3830
3943
  const errors = validateWidget(value, widget['widget-data-validation'], widget['widget-required'], skipRequired);
3831
3944
  if (errors.length > 0) {
@@ -3860,52 +3973,6 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
3860
3973
  return isValid;
3861
3974
  };
3862
3975
 
3863
- /** Table-style widgets that bind to an array path in the store / schema. */
3864
- function isTableLikeWidget(widget) {
3865
- const w = widget.widget;
3866
- /** widget-type union in types omits legacy values like simple-table still used at runtime */
3867
- const t = widget['widget-type'];
3868
- return (w === 'table' ||
3869
- w === 'dialog-table' ||
3870
- w === 'simple-table' ||
3871
- t === 'table' ||
3872
- t === 'simple-table');
3873
- }
3874
- /**
3875
- * Resolve `records` for section save payloads.
3876
- * - Back-compat: path ending in `.records` (e.g. `regId.records`)
3877
- * - Else: first array snapshot at a string `widget-data-path` on a table-like widget
3878
- * (e.g. `household.members` for dialog-table)
3879
- */
3880
- function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
3881
- const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
3882
- if (convention) {
3883
- return convention[1];
3884
- }
3885
- const tablePaths = [];
3886
- sectionWidgets.forEach((widget) => {
3887
- if (!isTableLikeWidget(widget))
3888
- return;
3889
- const p = widget['widget-data-path'];
3890
- if (typeof p === 'string' && p.length > 0) {
3891
- tablePaths.push(p);
3892
- }
3893
- else if (p && typeof p === 'object') {
3894
- Object.values(p).forEach((sub) => {
3895
- if (typeof sub === 'string' && sub.length > 0)
3896
- tablePaths.push(sub);
3897
- });
3898
- }
3899
- });
3900
- for (const path of tablePaths) {
3901
- const val = snapshot[path];
3902
- if (Array.isArray(val)) {
3903
- return val;
3904
- }
3905
- }
3906
- return [];
3907
- }
3908
-
3909
3976
  /** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
3910
3977
  const READONLY_VALUE_ROW_ROOT_CLASSES = [
3911
3978
  'TextDisplayWidget',
@@ -5197,11 +5264,6 @@ const SectionsContainer = ({ sections, dataSourceRequestHandler: propDataSourceR
5197
5264
  // Stable ref for namespace so formHandle useMemo doesn't depend on the (possibly inline) function identity
5198
5265
  const namespaceRef = React.useRef(namespace);
5199
5266
  namespaceRef.current = namespace;
5200
- // Stable ref for sections so formHandle useMemo doesn't depend on the (possibly unstable) array reference.
5201
- // Without this, an inline sections={[...]} prop would recreate formHandle every render, causing
5202
- // onFormReady to fire every render → host setState → infinite re-render loop.
5203
- const safeSectionsRef = React.useRef(safeSections);
5204
- safeSectionsRef.current = safeSections;
5205
5267
  // Stable refs so formHandle closure can access current mode and accordion setter without stale captures
5206
5268
  const modeRef = React.useRef(mode);
5207
5269
  modeRef.current = mode;
@@ -5250,9 +5312,6 @@ const SectionsContainer = ({ sections, dataSourceRequestHandler: propDataSourceR
5250
5312
  }, [mode, safeSections.length, expandedSectionIndex]);
5251
5313
  const UNSAVED_CHANGES_ERROR = 'Unsaved changes detected. Please save all sections before submitting.';
5252
5314
  // Form handle for onFormReady - allows host to validate and get all section data from its own Submit button
5253
- // IMPORTANT: safeSections is intentionally accessed via safeSectionsRef.current (not closed over directly)
5254
- // so that this memo never depends on the sections array reference. This prevents an infinite re-render
5255
- // loop when the host passes an unstable sections prop (e.g. inline array or derived state).
5256
5315
  const formHandle = React.useMemo(() => {
5257
5316
  const getValues = () => store.getState().widget?.values || {};
5258
5317
  const getNamespace = (section, index) => {
@@ -5274,11 +5333,10 @@ const SectionsContainer = ({ sections, dataSourceRequestHandler: propDataSourceR
5274
5333
  if (modeRef.current !== 'IntakeForm')
5275
5334
  checkNoUnsavedChanges();
5276
5335
  const values = getValues();
5277
- const sections = safeSectionsRef.current;
5278
5336
  let allValid = true;
5279
5337
  let firstInvalidIndex = null;
5280
- for (let i = 0; i < sections.length; i++) {
5281
- const section = sections[i];
5338
+ for (let i = 0; i < safeSections.length; i++) {
5339
+ const section = safeSections[i];
5282
5340
  const ns = getNamespace(section, i);
5283
5341
  const sectionToValidate = ns ? namespaceSectionConfig(section, ns) : section;
5284
5342
  const valid = sectionValidate(sectionToValidate, values, dispatch);
@@ -5298,11 +5356,10 @@ const SectionsContainer = ({ sections, dataSourceRequestHandler: propDataSourceR
5298
5356
  if (modeRef.current !== 'IntakeForm')
5299
5357
  checkNoUnsavedChanges();
5300
5358
  const values = getValues();
5301
- const sections = safeSectionsRef.current;
5302
5359
  const results = [];
5303
5360
  let firstInvalidIndex = null;
5304
- for (let i = 0; i < sections.length; i++) {
5305
- const section = sections[i];
5361
+ for (let i = 0; i < safeSections.length; i++) {
5362
+ const section = safeSections[i];
5306
5363
  const ns = getNamespace(section, i);
5307
5364
  const sectionToValidate = ns ? namespaceSectionConfig(section, ns) : section;
5308
5365
  const valid = sectionValidate(sectionToValidate, values, dispatch);
@@ -5324,18 +5381,16 @@ const SectionsContainer = ({ sections, dataSourceRequestHandler: propDataSourceR
5324
5381
  },
5325
5382
  getStructuredData: () => {
5326
5383
  const values = getValues();
5327
- const sections = safeSectionsRef.current;
5328
5384
  const results = [];
5329
- for (let i = 0; i < sections.length; i++) {
5330
- const section = sections[i];
5385
+ for (let i = 0; i < safeSections.length; i++) {
5386
+ const section = safeSections[i];
5331
5387
  const ns = getNamespace(section, i);
5332
5388
  results.push(buildSectionChanges(section, values, ns));
5333
5389
  }
5334
5390
  return results;
5335
5391
  },
5336
5392
  };
5337
- // eslint-disable-next-line react-hooks/exhaustive-deps
5338
- }, [store, dispatch]); // safeSections intentionally omitted — accessed via safeSectionsRef
5393
+ }, [store, dispatch, safeSections]);
5339
5394
  // Call onFormReady when form is ready (sections loaded)
5340
5395
  React.useEffect(() => {
5341
5396
  if (onFormReady && safeSections.length > 0) {
@@ -7403,7 +7458,7 @@ const NumberInputWidget = ({ config }) => {
7403
7458
  if (parsed === null) {
7404
7459
  // Allow empty input or partial input (e.g., "-", ".")
7405
7460
  if (inputValue === '' || inputValue === '-' || inputValue === '.') {
7406
- onChange('');
7461
+ onChange(null);
7407
7462
  }
7408
7463
  // Don't update if invalid - let user continue typing
7409
7464
  return;
@@ -7527,6 +7582,8 @@ const BooleanWidget = ({ config }) => {
7527
7582
  return labels[representation];
7528
7583
  }, [representation, formatConfig, translateConfig]);
7529
7584
  const { trueLabel, falseLabel } = getLabels();
7585
+ const unsetLabel = React.useMemo(() => translateConfig(formatConfig?.booleanUnsetLabel || 'Not set'), [formatConfig?.booleanUnsetLabel, translateConfig]);
7586
+ const radioGroupName = `${widgetConfig['widget-id'] ?? 'boolean'}__${React.useId().replace(/:/g, '')}`;
7530
7587
  // Determine current value (handle null/undefined)
7531
7588
  const currentValue = React.useMemo(() => {
7532
7589
  if (value === null || value === undefined) {
@@ -7558,7 +7615,7 @@ const BooleanWidget = ({ config }) => {
7558
7615
  const label = translateConfig(widgetConfig['widget-label']);
7559
7616
  let displayValue = '';
7560
7617
  if (currentValue === null) {
7561
- displayValue = '-';
7618
+ displayValue = '';
7562
7619
  }
7563
7620
  else if (currentValue === true) {
7564
7621
  displayValue = trueLabel;
@@ -7570,18 +7627,20 @@ const BooleanWidget = ({ config }) => {
7570
7627
  }
7571
7628
  // Render based on control type
7572
7629
  if (controlType === 'checkbox') {
7573
- 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.jsxs("label", { className: "flex items-center cursor-pointer", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: currentValue === true, onChange: handleCheckboxChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], className: "mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700", children: currentValue === true ? trueLabel : (currentValue === false ? falseLabel : '-') })] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
7630
+ 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] }))] })] }) }));
7574
7631
  }
7575
7632
  if (controlType === 'radio') {
7576
7633
  const containerClass = orientation === 'horizontal'
7577
- ? 'flex flex-row space-x-4'
7578
- : 'flex flex-col space-y-2';
7579
- 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.jsxs("div", { className: containerClass, onBlur: onBlur, children: [allowUnset && (jsxRuntimeExports.jsxs("label", { className: `flex items-center cursor-pointer ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : ''}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: widgetConfig['widget-id'], checked: currentValue === null, onChange: () => handleRadioChange(null), disabled: !isEnabled || widgetConfig['widget-readonly'], className: "mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700", children: "-" })] })), jsxRuntimeExports.jsxs("label", { className: `flex items-center cursor-pointer ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : ''}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: widgetConfig['widget-id'], checked: currentValue === true, onChange: () => handleRadioChange(true), disabled: !isEnabled || widgetConfig['widget-readonly'], className: "mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700", children: trueLabel })] }), jsxRuntimeExports.jsxs("label", { className: `flex items-center cursor-pointer ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : ''}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: widgetConfig['widget-id'], checked: currentValue === false, onChange: () => handleRadioChange(false), disabled: !isEnabled || widgetConfig['widget-readonly'], className: "mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700", children: falseLabel })] })] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
7634
+ ? 'flex flex-row flex-wrap items-baseline gap-x-4 gap-y-2'
7635
+ : 'flex flex-col items-start gap-2';
7636
+ const radioDisabled = !isEnabled || widgetConfig['widget-readonly'];
7637
+ const optionDisabledClass = radioDisabled ? 'opacity-50 cursor-not-allowed' : '';
7638
+ 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] }))] })] }) }));
7580
7639
  }
7581
7640
  // Toggle/switch control type
7582
- 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 sm:min-w-[150px] 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.jsxs("div", { className: "flex items-center space-x-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
7641
+ 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
7583
7642
  ? 'bg-blue-600 text-white border-blue-600'
7584
- : '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: "-" })), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(true), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === true
7643
+ : '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
7585
7644
  ? 'bg-blue-600 text-white border-blue-600'
7586
7645
  : '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
7587
7646
  ? 'bg-blue-600 text-white border-blue-600'
@@ -8292,7 +8351,7 @@ const CheckboxWidget = ({ config }) => {
8292
8351
  const displayValue = isChecked ? 'Yes' : 'No';
8293
8352
  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 }) })] }));
8294
8353
  }
8295
- 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.jsxs("label", { className: "flex items-center cursor-pointer", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => onChange(e.target.checked), onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], className: "mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-sm 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] }))] })] }) }));
8354
+ 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] }))] })] }) }));
8296
8355
  }
8297
8356
  // Multiple checkboxes (with data source) - for array values
8298
8357
  // Process and sort options if needed
@@ -8335,7 +8394,7 @@ const CheckboxWidget = ({ config }) => {
8335
8394
  switch (layout) {
8336
8395
  case 'horizontal':
8337
8396
  return {
8338
- className: 'flex flex-row flex-wrap gap-4',
8397
+ className: 'flex flex-row flex-wrap items-baseline gap-4',
8339
8398
  style: undefined,
8340
8399
  };
8341
8400
  case 'grid':
@@ -8348,7 +8407,7 @@ const CheckboxWidget = ({ config }) => {
8348
8407
  case 'vertical':
8349
8408
  default:
8350
8409
  return {
8351
- className: 'flex flex-col space-y-2',
8410
+ className: 'flex flex-col gap-2',
8352
8411
  style: undefined,
8353
8412
  };
8354
8413
  }
@@ -8362,7 +8421,7 @@ const CheckboxWidget = ({ config }) => {
8362
8421
  : '-';
8363
8422
  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 }) })] }));
8364
8423
  }
8365
- 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("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: `flex items-center cursor-pointer ${!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: "mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-sm 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] }))] })] }) }));
8424
+ 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] }))] })] }) }));
8366
8425
  };
8367
8426
 
8368
8427
  const SimpleTableWidget = ({ config }) => {
@@ -9401,6 +9460,27 @@ const DialogTableWidget = ({ config }) => {
9401
9460
  }, [formData, columns, storeValues, dialogFieldWidgetId]);
9402
9461
  const saveDialog = React.useCallback(() => {
9403
9462
  const payload = collectMergedRowPayload();
9463
+ let hasErrors = false;
9464
+ columns.forEach((col) => {
9465
+ const key = col['column-key'];
9466
+ const cellWidgetId = dialogFieldWidgetId(key);
9467
+ const isColReadonly = isReadonly || col['widget-readonly'] === true;
9468
+ if (isColReadonly)
9469
+ return;
9470
+ const cellValue = payload[key];
9471
+ const validationErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
9472
+ if (validationErrors && validationErrors.length > 0) {
9473
+ hasErrors = true;
9474
+ dispatch(setError({ widgetId: cellWidgetId, errors: validationErrors }));
9475
+ dispatch(setTouched({ widgetId: cellWidgetId, touched: true }));
9476
+ }
9477
+ else {
9478
+ dispatch(setError({ widgetId: cellWidgetId, errors: [] }));
9479
+ }
9480
+ });
9481
+ if (hasErrors) {
9482
+ return;
9483
+ }
9404
9484
  if (dialogMode === 'add') {
9405
9485
  const savedRow = { ...payload, edit_action: 'ADD' };
9406
9486
  onChange([...rows, savedRow]);
@@ -9416,7 +9496,7 @@ const DialogTableWidget = ({ config }) => {
9416
9496
  onChange(newRows);
9417
9497
  closeDialog();
9418
9498
  }
9419
- }, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex]);
9499
+ }, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
9420
9500
  const deleteRow = React.useCallback((rowIndex) => {
9421
9501
  const newRows = rows.filter((_, i) => i !== rowIndex);
9422
9502
  onChange(newRows);
@@ -9767,10 +9847,13 @@ const TextAreaWidget = ({ config }) => {
9767
9847
  // For readonly mode, render as preformatted text using <pre> tag
9768
9848
  if (isReadonly) {
9769
9849
  const displayValue = getStringValue() || '-';
9770
- return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] TextAreaDisplayWidget 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("pre", { className: "text-base text-gray-900 font-medium whitespace-pre-wrap", title: String(displayValue), style: {
9850
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] TextAreaDisplayWidget 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", { title: String(displayValue), className: "text-base text-gray-900 font-medium overflow-y-auto whitespace-pre-wrap break-words", style: {
9771
9851
  fontFamily: 'Roboto, sans-serif',
9772
- margin: 0,
9773
- padding: 0,
9852
+ height: '56px',
9853
+ minHeight: '56px',
9854
+ maxHeight: '56px',
9855
+ lineHeight: '20px',
9856
+ padding: '8px 0',
9774
9857
  backgroundColor: 'transparent',
9775
9858
  border: 'none',
9776
9859
  }, children: displayValue }) })] }));
@@ -10239,20 +10322,29 @@ const HeaderSectionWidget = ({ config }) => {
10239
10322
  .${cls} .hdr-field-row {
10240
10323
  display: flex;
10241
10324
  align-items: flex-start;
10242
- gap: 0.5rem;
10243
10325
  font-size: 1rem;
10244
10326
  line-height: 1.6;
10245
10327
  }
10246
10328
 
10247
10329
  .${cls} .hdr-field-label {
10330
+ width: 50%;
10331
+ flex: 0 0 50%;
10248
10332
  color: rgba(0, 0, 0, 0.5);
10249
10333
  font-weight: 400;
10250
10334
  white-space: nowrap;
10335
+ overflow: hidden;
10336
+ text-overflow: ellipsis;
10337
+ padding-right: 4px;
10251
10338
  }
10252
10339
 
10253
10340
  .${cls} .hdr-field-value {
10341
+ width: 50%;
10342
+ flex: 0 0 50%;
10254
10343
  color: var(--owt-color-text, #111827);
10255
10344
  font-weight: 500;
10345
+ white-space: nowrap;
10346
+ overflow: hidden;
10347
+ text-overflow: ellipsis;
10256
10348
  }
10257
10349
 
10258
10350
  .${cls} .hdr-status-badge {
@@ -10262,24 +10354,38 @@ const HeaderSectionWidget = ({ config }) => {
10262
10354
  font-size: 0.75rem;
10263
10355
  font-weight: 600;
10264
10356
  color: #fff;
10357
+ max-width: 100%;
10358
+ overflow: hidden;
10359
+ text-overflow: ellipsis;
10360
+ white-space: nowrap;
10265
10361
  }
10266
10362
 
10267
10363
  .${cls} .hdr-meta-row {
10268
10364
  display: flex;
10269
10365
  align-items: baseline;
10270
- gap: 0.35rem;
10271
10366
  font-size: 1rem;
10272
10367
  line-height: 1.6;
10273
10368
  }
10274
10369
 
10275
10370
  .${cls} .hdr-meta-label {
10371
+ width: 50%;
10372
+ flex: 0 0 50%;
10276
10373
  color: rgba(0, 0, 0, 0.5);
10277
10374
  font-weight: 400;
10375
+ white-space: nowrap;
10376
+ overflow: hidden;
10377
+ text-overflow: ellipsis;
10378
+ padding-right: 4px;
10278
10379
  }
10279
10380
 
10280
10381
  .${cls} .hdr-meta-value {
10382
+ width: 50%;
10383
+ flex: 0 0 50%;
10281
10384
  color: var(--owt-color-text, #111827);
10282
10385
  font-weight: 500;
10386
+ white-space: nowrap;
10387
+ overflow: hidden;
10388
+ text-overflow: ellipsis;
10283
10389
  }
10284
10390
 
10285
10391
  .${cls} .hdr-select {
@@ -10343,7 +10449,7 @@ const HeaderSectionWidget = ({ config }) => {
10343
10449
  .parentElement?.querySelector('.hdr-avatar-placeholder');
10344
10450
  if (placeholder)
10345
10451
  placeholder.style.display = 'flex';
10346
- } })) : 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: () => {
10452
+ } })) : 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: () => {
10347
10453
  if (isReasonMissing)
10348
10454
  setShowReasonRequired(true);
10349
10455
  }, onChange: (e) => {
@@ -10351,7 +10457,7 @@ const HeaderSectionWidget = ({ config }) => {
10351
10457
  if (showReasonRequired && String(e.target.value || '').trim().length > 0) {
10352
10458
  setShowReasonRequired(false);
10353
10459
  }
10354
- } }), !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] }) })] })] }));
10460
+ } }), !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] }) })] })] }));
10355
10461
  };
10356
10462
 
10357
10463
  function getValueByPathOrKey(obj, path) {