@openg2p/registry-widgets 1.1.2-dev.1 → 1.1.2-dev.10

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.
Files changed (54) hide show
  1. package/dist/assets/index.d.ts +3 -1
  2. package/dist/assets/index.d.ts.map +1 -1
  3. package/dist/components/SectionBuilder/schemas.d.ts +204 -0
  4. package/dist/components/SectionBuilder/schemas.d.ts.map +1 -1
  5. package/dist/components/SectionRenderer.d.ts.map +1 -1
  6. package/dist/components/WidgetFieldLabel.d.ts +11 -0
  7. package/dist/components/WidgetFieldLabel.d.ts.map +1 -0
  8. package/dist/hooks/useBaseWidget.d.ts +2 -0
  9. package/dist/hooks/useBaseWidget.d.ts.map +1 -1
  10. package/dist/hooks/useGeoWidgetCascade.d.ts.map +1 -1
  11. package/dist/index.d.ts +89 -28
  12. package/dist/index.esm.js +1655 -534
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +1671 -532
  15. package/dist/index.js.map +1 -1
  16. package/dist/registry/defaultWidgets.d.ts.map +1 -1
  17. package/dist/types/index.d.ts +11 -1
  18. package/dist/types/index.d.ts.map +1 -1
  19. package/dist/utils/conditions.d.ts +17 -11
  20. package/dist/utils/conditions.d.ts.map +1 -1
  21. package/dist/utils/dataSource.d.ts +6 -0
  22. package/dist/utils/dataSource.d.ts.map +1 -1
  23. package/dist/utils/geoHierarchy.d.ts +42 -0
  24. package/dist/utils/geoHierarchy.d.ts.map +1 -1
  25. package/dist/utils/schemaNamespace.d.ts.map +1 -1
  26. package/dist/utils/schemaTranslation.d.ts.map +1 -1
  27. package/dist/utils/sectionRevert.d.ts +24 -0
  28. package/dist/utils/sectionRevert.d.ts.map +1 -0
  29. package/dist/utils/sectionValidate.d.ts.map +1 -1
  30. package/dist/widgets/ArrayWidget.d.ts.map +1 -1
  31. package/dist/widgets/BooleanWidget.d.ts.map +1 -1
  32. package/dist/widgets/CheckboxWidget.d.ts.map +1 -1
  33. package/dist/widgets/CurrencyInputWidget.d.ts.map +1 -1
  34. package/dist/widgets/DateInputWidget.d.ts.map +1 -1
  35. package/dist/widgets/DateTimeInputWidget.d.ts.map +1 -1
  36. package/dist/widgets/DialogTableWidget.d.ts +0 -13
  37. package/dist/widgets/DialogTableWidget.d.ts.map +1 -1
  38. package/dist/widgets/FileInputWidget.d.ts.map +1 -1
  39. package/dist/widgets/HeaderSectionWidget.d.ts.map +1 -1
  40. package/dist/widgets/IterableAccordionWidget.d.ts.map +1 -1
  41. package/dist/widgets/MultiSelectWidget.d.ts +7 -0
  42. package/dist/widgets/MultiSelectWidget.d.ts.map +1 -0
  43. package/dist/widgets/NumberInputWidget.d.ts.map +1 -1
  44. package/dist/widgets/PhoneInputWidget.d.ts.map +1 -1
  45. package/dist/widgets/RadioWidget.d.ts.map +1 -1
  46. package/dist/widgets/RegisterLookupWidget.d.ts +5 -0
  47. package/dist/widgets/RegisterLookupWidget.d.ts.map +1 -0
  48. package/dist/widgets/SelectWidget.d.ts.map +1 -1
  49. package/dist/widgets/TableWidget.d.ts.map +1 -1
  50. package/dist/widgets/TextAreaWidget.d.ts.map +1 -1
  51. package/dist/widgets/TextInputWidget.d.ts.map +1 -1
  52. package/dist/widgets/index.d.ts +2 -0
  53. package/dist/widgets/index.d.ts.map +1 -1
  54. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -403,6 +403,18 @@ const createZodSchema = (validation, required = false) => {
403
403
  return schema;
404
404
  };
405
405
 
406
+ const normalizeBooleanLike = (val) => {
407
+ if (val === true || val === 1)
408
+ return true;
409
+ if (val === false || val === 0 || val === null || val === undefined || val === '') {
410
+ return false;
411
+ }
412
+ if (typeof val === 'string') {
413
+ const normalized = val.trim().toLowerCase();
414
+ return normalized === 'true' || normalized === 'yes' || normalized === '1';
415
+ }
416
+ return Boolean(val);
417
+ };
406
418
  /**
407
419
  * Evaluate condition against field value
408
420
  */
@@ -411,6 +423,9 @@ const evaluateCondition = (condition, allValues) => {
411
423
  const { operator, value } = condition;
412
424
  switch (operator) {
413
425
  case 'equals':
426
+ if (typeof value === 'boolean' || typeof fieldValue === 'boolean') {
427
+ return normalizeBooleanLike(fieldValue) === normalizeBooleanLike(value);
428
+ }
414
429
  return fieldValue === value;
415
430
  case 'notEquals':
416
431
  return fieldValue !== value;
@@ -443,37 +458,62 @@ const evaluateCondition = (condition, allValues) => {
443
458
  }
444
459
  };
445
460
  /**
446
- * Check if widget should be visible based on conditions
461
+ * Normalize widget-data-options into a sequential list of action rules.
462
+ * Supports legacy single { action, condition } and new { actions: [...] }.
447
463
  */
448
- const shouldShowWidget = (options, allValues) => {
449
- if (!options?.condition) {
450
- return true;
464
+ const normalizeOptionRules = (options) => {
465
+ if (!options) {
466
+ return [];
451
467
  }
452
- const conditionResult = evaluateCondition(options.condition, allValues);
453
- if (options.action === 'show') {
454
- return conditionResult;
468
+ if (Array.isArray(options.actions) && options.actions.length > 0) {
469
+ return options.actions.filter((rule) => !!rule?.action);
455
470
  }
456
- if (options.action === 'hide') {
457
- return !conditionResult;
471
+ if (options.action && options.condition) {
472
+ return [{ action: options.action, condition: options.condition }];
458
473
  }
459
- return true;
474
+ return [];
475
+ };
476
+ const hasVisibilityRules = (options) => {
477
+ return normalizeOptionRules(options).some((rule) => rule.action === 'show' || rule.action === 'hide');
460
478
  };
461
479
  /**
462
- * Check if widget should be enabled based on conditions
480
+ * Evaluate widget-data-options rules sequentially.
481
+ * show/hide and enable/disable only affect visibility and enabled state.
482
+ * require is independent: required = widget-required OR require-condition-match.
463
483
  */
464
- const shouldEnableWidget = (options, allValues) => {
465
- if (!options?.condition) {
466
- return true;
467
- }
468
- const conditionResult = evaluateCondition(options.condition, allValues);
469
- if (options.action === 'enable') {
470
- return conditionResult;
471
- }
472
- if (options.action === 'disable') {
473
- return !conditionResult;
484
+ const evaluateWidgetConditions = (options, allValues, baseRequired = false) => {
485
+ let visible = true;
486
+ let enabled = true;
487
+ let required = baseRequired;
488
+ const rules = normalizeOptionRules(options);
489
+ for (const rule of rules) {
490
+ if (!rule.condition) {
491
+ continue;
492
+ }
493
+ const match = evaluateCondition(rule.condition, allValues);
494
+ switch (rule.action) {
495
+ case 'show':
496
+ visible = match;
497
+ break;
498
+ case 'hide':
499
+ visible = !match;
500
+ break;
501
+ case 'enable':
502
+ enabled = match;
503
+ break;
504
+ case 'disable':
505
+ enabled = !match;
506
+ break;
507
+ case 'require':
508
+ required = baseRequired || match;
509
+ break;
510
+ }
474
511
  }
475
- return true;
512
+ return { visible, enabled, required };
476
513
  };
514
+ const shouldShowWidget = (options, allValues) => evaluateWidgetConditions(options, allValues).visible;
515
+ const shouldEnableWidget = (options, allValues) => evaluateWidgetConditions(options, allValues).enabled;
516
+ const shouldRequireWidget = (options, allValues, baseRequired = false) => evaluateWidgetConditions(options, allValues, baseRequired).required;
477
517
 
478
518
  /**
479
519
  * Format number with thousand and decimal separators
@@ -1043,6 +1083,67 @@ const formatValue = (value, format, widgetType) => {
1043
1083
  return value?.toString() || '';
1044
1084
  };
1045
1085
 
1086
+ const apiDataSourceCache = new Map();
1087
+ const apiDataSourceInflight = new Map();
1088
+ function buildApiRequestContext(dataSource, allValues, levelId) {
1089
+ let depValue = null;
1090
+ if (dataSource.dependsOn) {
1091
+ if (dataSource.dependsOn.includes('.')) {
1092
+ depValue = getValueByPath(allValues, dataSource.dependsOn);
1093
+ }
1094
+ else {
1095
+ depValue = resolveWidgetIdValue(allValues, dataSource.dependsOn);
1096
+ }
1097
+ if (depValue === null || depValue === undefined || depValue === '') {
1098
+ return null;
1099
+ }
1100
+ }
1101
+ const method = dataSource.method || 'GET';
1102
+ const staticParams = { ...dataSource.params };
1103
+ const standardFields = ['type', 'service', 'endpoint', 'url', 'method', 'dependsOn', 'valueKey', 'labelKey', 'headers', 'body', 'params', 'level_id'];
1104
+ for (const [key, value] of Object.entries(dataSource)) {
1105
+ if (!standardFields.includes(key) && value !== undefined && value !== null) {
1106
+ staticParams[key] = value;
1107
+ }
1108
+ }
1109
+ if (levelId) {
1110
+ staticParams.level_id = levelId;
1111
+ }
1112
+ const requestParams = { ...staticParams };
1113
+ if (dataSource.dependsOn && depValue !== null && depValue !== undefined) {
1114
+ const parentValueId = typeof depValue === 'object' && depValue !== null
1115
+ ? (depValue.level_value_id || depValue.id || depValue.value || depValue)
1116
+ : depValue;
1117
+ if (staticParams.level_id) {
1118
+ requestParams.parent_level_value_id = parentValueId;
1119
+ }
1120
+ else {
1121
+ const paramKey = dataSource.dependsOn.split('.').pop() || 'filter';
1122
+ requestParams[paramKey] = parentValueId;
1123
+ }
1124
+ }
1125
+ else if (staticParams.level_id) {
1126
+ requestParams.parent_level_value_id = '';
1127
+ }
1128
+ const service = dataSource.service;
1129
+ const endpoint = dataSource.endpoint;
1130
+ if (!service || !endpoint) {
1131
+ return null;
1132
+ }
1133
+ return { service, endpoint, method, requestParams };
1134
+ }
1135
+ function buildApiDataSourceCacheKey(service, endpoint, method, requestParams) {
1136
+ return `${service}|${endpoint}|${method}|${JSON.stringify(requestParams)}`;
1137
+ }
1138
+ /** Return cached API options when already fetched (e.g. duplicate table cells). */
1139
+ function getCachedApiDataSource(dataSource, allValues, levelId) {
1140
+ const context = buildApiRequestContext(dataSource, allValues, levelId);
1141
+ if (!context) {
1142
+ return undefined;
1143
+ }
1144
+ const cacheKey = buildApiDataSourceCacheKey(context.service, context.endpoint, context.method, context.requestParams);
1145
+ return apiDataSourceCache.get(cacheKey);
1146
+ }
1046
1147
  /**
1047
1148
  * Get static data source options
1048
1149
  */
@@ -1060,98 +1161,33 @@ const getApiDataSource = async (dataSource, allValues, dataSourceRequestHandler,
1060
1161
  return [];
1061
1162
  }
1062
1163
  try {
1063
- // Get dependency value if exists
1064
- // dependsOn can be either a data path (e.g., "person.address") or a widget-id
1065
- let depValue = null;
1066
- if (dataSource.dependsOn) {
1067
- if (dataSource.dependsOn.includes('.')) {
1068
- depValue = getValueByPath(allValues, dataSource.dependsOn);
1069
- }
1070
- else {
1071
- depValue = resolveWidgetIdValue(allValues, dataSource.dependsOn);
1072
- }
1073
- if (depValue === null || depValue === undefined || depValue === '') {
1074
- // If dependency is empty, return empty array
1075
- return [];
1076
- }
1077
- }
1078
- // Build request parameters
1079
- const method = dataSource.method || 'GET';
1080
- // Extract static params from dataSource
1081
- // Include explicit params object and any additional fields (like level_id)
1082
- const staticParams = { ...dataSource.params };
1083
- // Extract additional fields that aren't part of the standard ApiDataSource interface
1084
- // These are fields like level_id that might be directly on the dataSource
1085
- // BUT: level_id should come from widget-geo-config.level, not from dataSource
1086
- const standardFields = ['type', 'service', 'endpoint', 'url', 'method', 'dependsOn', 'valueKey', 'labelKey', 'headers', 'body', 'params', 'level_id'];
1087
- for (const [key, value] of Object.entries(dataSource)) {
1088
- if (!standardFields.includes(key) && value !== undefined && value !== null) {
1089
- staticParams[key] = value;
1090
- }
1091
- }
1092
- // If levelId is provided (from widget-geo-config.level), use it instead of any level_id in dataSource
1093
- if (levelId) {
1094
- staticParams.level_id = levelId;
1095
- }
1096
- // Build request params object
1097
- const requestParams = { ...staticParams };
1098
- // Add dependency value to params
1099
- if (dataSource.dependsOn && depValue !== null && depValue !== undefined) {
1100
- // Extract the actual value ID if depValue is an object
1101
- const parentValueId = typeof depValue === 'object' && depValue !== null
1102
- ? (depValue.level_value_id || depValue.id || depValue.value || depValue)
1103
- : depValue;
1104
- // For geo APIs, use parent_level_value_id
1105
- if (staticParams.level_id) {
1106
- requestParams.parent_level_value_id = parentValueId;
1107
- }
1108
- else {
1109
- // For other APIs, use the dependency field name as param key
1110
- const paramKey = dataSource.dependsOn.split('.').pop() || 'filter';
1111
- requestParams[paramKey] = parentValueId;
1112
- }
1113
- }
1114
- else if (staticParams.level_id) {
1115
- // First level has no parent, send empty string as many OpenG2P APIs expect it
1116
- requestParams.parent_level_value_id = "";
1117
- }
1118
- // Get service mnemonic and endpoint (required)
1119
- const service = dataSource.service;
1120
- const endpoint = dataSource.endpoint;
1121
- if (!service) {
1122
- console.error('[getApiDataSource] API data source missing service mnemonic. Use "service" field instead of "url"');
1123
- return [];
1124
- }
1125
- if (!endpoint) {
1126
- console.error('[getApiDataSource] API data source missing endpoint. Use "endpoint" field to specify the operation (e.g., "get_g2p_geo_level_values")');
1164
+ const context = buildApiRequestContext(dataSource, allValues, levelId);
1165
+ if (!context) {
1127
1166
  return [];
1128
1167
  }
1129
- // Call handler let any throw propagate to the outer catch so it is logged once
1130
- // by useBaseWidget rather than double-logged here (which can cascade when
1131
- // intercept-console-error.js converts console.error calls into thrown errors).
1132
- const response = await dataSourceRequestHandler(service, endpoint, method, requestParams, {
1133
- headers: dataSource.headers,
1134
- });
1135
- // Handle OpenG2P response format (response_body.response_payload)
1136
- if (response && typeof response === 'object') {
1137
- if (response.response_body?.response_payload && Array.isArray(response.response_body.response_payload)) {
1138
- return response.response_body.response_payload;
1139
- }
1140
- }
1141
- // Handle array response
1142
- if (Array.isArray(response)) {
1143
- return response;
1168
+ const { service, endpoint, method, requestParams } = context;
1169
+ const cacheKey = buildApiDataSourceCacheKey(service, endpoint, method, requestParams);
1170
+ const cached = apiDataSourceCache.get(cacheKey);
1171
+ if (cached) {
1172
+ return cached;
1173
+ }
1174
+ const inflight = apiDataSourceInflight.get(cacheKey);
1175
+ if (inflight) {
1176
+ return inflight;
1177
+ }
1178
+ const fetchPromise = (async () => {
1179
+ const response = await dataSourceRequestHandler(service, endpoint, method, requestParams, { headers: dataSource.headers });
1180
+ const parsed = Array.isArray(response) ? response : [];
1181
+ apiDataSourceCache.set(cacheKey, parsed);
1182
+ return parsed;
1183
+ })();
1184
+ apiDataSourceInflight.set(cacheKey, fetchPromise);
1185
+ try {
1186
+ return await fetchPromise;
1144
1187
  }
1145
- // Handle object response (extract array from common keys)
1146
- if (response && typeof response === 'object') {
1147
- if (response.data && Array.isArray(response.data)) {
1148
- return response.data;
1149
- }
1150
- if (response.results && Array.isArray(response.results)) {
1151
- return response.results;
1152
- }
1188
+ finally {
1189
+ apiDataSourceInflight.delete(cacheKey);
1153
1190
  }
1154
- return [];
1155
1191
  }
1156
1192
  catch (error) {
1157
1193
  // Rethrow so useBaseWidget's catch can log it with full widget context
@@ -1937,6 +1973,98 @@ const WidgetProvider = ({ store, dataSourceRequestHandler, schemaData, translate
1937
1973
  return content;
1938
1974
  };
1939
1975
 
1976
+ /**
1977
+ * Custom hook for widget translations
1978
+ * Provides translation function with widget-specific namespace and fallback support
1979
+ */
1980
+ const useWidgetTranslation = () => {
1981
+ const { translate: translateFunction } = useWidgetContext();
1982
+ /**
1983
+ * Translate a key with flexible namespace support
1984
+ * Supports translation keys in various formats and direct strings
1985
+ *
1986
+ * Translation key formats supported:
1987
+ * - "widgets:common.addItem" - Namespaced key (for widget-specific translations)
1988
+ * - "Name" - Direct string (will be looked up in flat translation structure)
1989
+ * - "sections.personalDetails" - Nested key (for backward compatibility)
1990
+ *
1991
+ * With flat translation structure, direct strings like "Name" are automatically
1992
+ * translated by looking them up in the translation resources.
1993
+ *
1994
+ * @param keyOrString - Translation key (e.g., "widgets:common.addItem") or direct string (e.g., "Name")
1995
+ * @param options - Translation options (interpolation values, default value, etc.)
1996
+ * @returns Translated string or original string if translation not found
1997
+ */
1998
+ const translate = (keyOrString, options) => {
1999
+ if (!keyOrString) {
2000
+ return options?.defaultValue || '';
2001
+ }
2002
+ // Use the provided translation function or fallback to the key
2003
+ if (translateFunction) {
2004
+ return translateFunction(keyOrString, options) || options?.defaultValue || keyOrString;
2005
+ }
2006
+ // Fallback to key if no translation function available
2007
+ return options?.defaultValue || keyOrString;
2008
+ };
2009
+ /**
2010
+ * Translate widget config property
2011
+ * Attempts to translate the value, but if translation is not found,
2012
+ * returns the original value as-is (graceful fallback)
2013
+ *
2014
+ * This function will:
2015
+ * - Try to translate any string value
2016
+ * - If translation exists, use the translated value
2017
+ * - If translation doesn't exist (returns same value or throws), use original value
2018
+ * - This prevents errors when literal strings like "XXXX-XXXX-XXXX" are used
2019
+ */
2020
+ const translateConfig = (value, fallback) => {
2021
+ if (!value) {
2022
+ return fallback || '';
2023
+ }
2024
+ // Try to translate the value
2025
+ if (translateFunction) {
2026
+ try {
2027
+ // Pass defaultValue to ensure we get the original value if translation fails
2028
+ const translated = translateFunction(value, { defaultValue: value });
2029
+ // If translation returns empty, null, undefined, or the exact same value,
2030
+ // it means no translation was found - return the original value
2031
+ if (!translated || translated === value) {
2032
+ return value;
2033
+ }
2034
+ // Translation found, return it
2035
+ return translated;
2036
+ }
2037
+ catch (error) {
2038
+ // If translation throws an error (e.g., missing key warning), return original value
2039
+ return value;
2040
+ }
2041
+ }
2042
+ // No translation function available, return value as-is
2043
+ return value;
2044
+ };
2045
+ // No need of this getLanguage and changeLanguage functions
2046
+ /**
2047
+ * Get current language
2048
+ */
2049
+ // const getLanguage = (): string => {
2050
+ // return i18n.language || 'en';
2051
+ // };
2052
+ /**
2053
+ * Change language
2054
+ */
2055
+ // const changeLanguage = (lng: string): Promise<void> => {
2056
+ // return i18n.changeLanguage(lng).then(() => undefined);
2057
+ // };
2058
+ return {
2059
+ t: translate,
2060
+ translate,
2061
+ translateConfig,
2062
+ // getLanguage,
2063
+ // changeLanguage,
2064
+ // i18n: null,
2065
+ };
2066
+ };
2067
+
1940
2068
  /**
1941
2069
  * Geo Hierarchy Builder
1942
2070
  * Manages geo hierarchy state and builds hierarchy JSON structure
@@ -2116,12 +2244,145 @@ const geoHierarchyBuilder = new GeoHierarchyBuilder();
2116
2244
  /** Sentinel written to Redux when a geo level is cleared by cascade (distinct from "never set"). */
2117
2245
  const GEO_LEVEL_CLEARED = null;
2118
2246
  const geoWidgetParentRegistry = new Map();
2247
+ const geoWidgetConfigRegistry = new Map();
2119
2248
  function registerGeoWidgetParent(widgetId, parentWidgetId) {
2120
2249
  geoWidgetParentRegistry.set(widgetId, parentWidgetId || null);
2121
2250
  }
2122
2251
  function unregisterGeoWidgetParent(widgetId) {
2123
2252
  geoWidgetParentRegistry.delete(widgetId);
2124
2253
  }
2254
+ function registerGeoWidget(widgetId, geoConfig, dataPath) {
2255
+ if (typeof dataPath !== 'string') {
2256
+ return;
2257
+ }
2258
+ const parentWidgetId = geoConfig.parentWidgetId?.trim() ? geoConfig.parentWidgetId : null;
2259
+ registerGeoWidgetParent(widgetId, parentWidgetId);
2260
+ geoWidgetConfigRegistry.set(widgetId, {
2261
+ widgetId,
2262
+ parentWidgetId,
2263
+ level: geoConfig.level,
2264
+ geoConfig,
2265
+ dataPath,
2266
+ groupId: getGeoGroupId(dataPath),
2267
+ });
2268
+ }
2269
+ function unregisterGeoWidget(widgetId) {
2270
+ unregisterGeoWidgetParent(widgetId);
2271
+ geoWidgetConfigRegistry.delete(widgetId);
2272
+ }
2273
+ function orderGeoWidgetRegistrations(registrations) {
2274
+ if (registrations.length <= 1) {
2275
+ return registrations;
2276
+ }
2277
+ const roots = registrations.filter((entry) => !entry.parentWidgetId);
2278
+ if (roots.length === 0) {
2279
+ return registrations;
2280
+ }
2281
+ const ordered = [];
2282
+ let current = roots[0];
2283
+ const visited = new Set();
2284
+ while (current && !visited.has(current.widgetId)) {
2285
+ visited.add(current.widgetId);
2286
+ ordered.push(current);
2287
+ current = registrations.find((entry) => entry.parentWidgetId === current.widgetId);
2288
+ }
2289
+ return ordered.length > 0 ? ordered : registrations;
2290
+ }
2291
+ function resolveLevelValueId(rawValue) {
2292
+ if (rawValue === null || rawValue === undefined || rawValue === '') {
2293
+ return null;
2294
+ }
2295
+ if (typeof rawValue === 'string' || typeof rawValue === 'number') {
2296
+ return String(rawValue);
2297
+ }
2298
+ if (typeof rawValue === 'object') {
2299
+ const id = rawValue.level_value_id || rawValue.id || rawValue.value;
2300
+ return id != null && id !== '' ? String(id) : null;
2301
+ }
2302
+ return null;
2303
+ }
2304
+ function resolveStoredMnemonic(values, registration, valueId) {
2305
+ const stored = getWidgetValue(values, registration.dataPath, registration.widgetId);
2306
+ const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
2307
+ if (!Array.isArray(hierarchy)) {
2308
+ return undefined;
2309
+ }
2310
+ const levelData = hierarchy.find((entry) => entry.level === registration.level);
2311
+ if (levelData && String(levelData.level_value_id) === String(valueId)) {
2312
+ return levelData.level_value_mnemonic ? String(levelData.level_value_mnemonic) : undefined;
2313
+ }
2314
+ return undefined;
2315
+ }
2316
+ /** Resolve display mnemonic from cached dropdown options, then stored hierarchy. */
2317
+ function createGeoLevelMnemonicResolver(values, dataSources) {
2318
+ return (registration, valueId) => {
2319
+ const options = dataSources[registration.widgetId];
2320
+ const option = options?.find((entry) => String(entry.value) === String(valueId));
2321
+ if (option?.label) {
2322
+ return option.label;
2323
+ }
2324
+ return resolveStoredMnemonic(values, registration, valueId);
2325
+ };
2326
+ }
2327
+ /** Rebuild group hierarchy from widget values in parent→child order; stop at first missing level. */
2328
+ function rebuildGeoHierarchyFromRegistrations(groupId, values, registrations, resolveMnemonic) {
2329
+ const ordered = orderGeoWidgetRegistrations(registrations.filter((entry) => entry.groupId === groupId));
2330
+ geoHierarchyBuilder.clear(groupId);
2331
+ for (const registration of ordered) {
2332
+ const rawValue = resolveGeoWidgetLevelValue(values, registration.widgetId, registration.dataPath, registration.geoConfig);
2333
+ const valueId = resolveLevelValueId(rawValue);
2334
+ if (!valueId) {
2335
+ break;
2336
+ }
2337
+ const mnemonic = resolveMnemonic?.(registration, valueId) ??
2338
+ resolveStoredMnemonic(values, registration, valueId) ??
2339
+ valueId;
2340
+ geoHierarchyBuilder.addLevel(registration.level, valueId, mnemonic, groupId);
2341
+ }
2342
+ return geoHierarchyBuilder.buildHierarchyJson(groupId) !== null;
2343
+ }
2344
+ function collectGeoWidgetRegistrationsFromWidgets(widgets, namespace) {
2345
+ return widgets
2346
+ .filter((widget) => widget['widget-geo-config'] && typeof widget['widget-data-path'] === 'string')
2347
+ .map((widget) => {
2348
+ const originalWidgetId = widget['widget-id'];
2349
+ const originalDataPath = widget['widget-data-path'];
2350
+ const geoConfig = widget['widget-geo-config'];
2351
+ const widgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
2352
+ const parentWidgetId = geoConfig.parentWidgetId?.trim()
2353
+ ? (namespace ? `${namespace}__${geoConfig.parentWidgetId}` : geoConfig.parentWidgetId)
2354
+ : null;
2355
+ const dataPath = namespace ? `${namespace}.${originalDataPath}` : originalDataPath;
2356
+ return {
2357
+ widgetId,
2358
+ parentWidgetId,
2359
+ level: geoConfig.level,
2360
+ geoConfig,
2361
+ dataPath,
2362
+ groupId: getGeoGroupId(dataPath),
2363
+ };
2364
+ });
2365
+ }
2366
+ /** Reconcile all geo groups in section values before save. */
2367
+ function reconcileGeoHierarchiesInValues(values, registrations, dataSources = {}) {
2368
+ const groupIds = [...new Set(registrations.map((entry) => entry.groupId))];
2369
+ let updatedValues = values;
2370
+ const resolveMnemonic = createGeoLevelMnemonicResolver(updatedValues, dataSources);
2371
+ for (const groupId of groupIds) {
2372
+ const groupRegistrations = registrations.filter((entry) => entry.groupId === groupId);
2373
+ const dataPath = groupRegistrations[0]?.dataPath;
2374
+ const widgetId = groupRegistrations[0]?.widgetId;
2375
+ if (!dataPath || !widgetId) {
2376
+ continue;
2377
+ }
2378
+ rebuildGeoHierarchyFromRegistrations(groupId, updatedValues, groupRegistrations, resolveMnemonic);
2379
+ updatedValues = applySharedGeoHierarchyToValues(updatedValues, groupId, dataPath, widgetId);
2380
+ }
2381
+ return updatedValues;
2382
+ }
2383
+ function getGeoWidgetRegistrationsInGroup(groupId) {
2384
+ return orderGeoWidgetRegistrations([...geoWidgetConfigRegistry.values()].filter((entry) => entry.groupId === groupId));
2385
+ }
2125
2386
  /** True when changedWidgetId is any upstream geo parent of widgetId (not only immediate parent). */
2126
2387
  function isUpstreamGeoAncestor(changedWidgetId, widgetId, immediateParentWidgetId) {
2127
2388
  if (changedWidgetId === widgetId) {
@@ -2136,6 +2397,42 @@ function isUpstreamGeoAncestor(changedWidgetId, widgetId, immediateParentWidgetI
2136
2397
  }
2137
2398
  return false;
2138
2399
  }
2400
+ /** Group id for geo widgets sharing the same register prefix (e.g. `{registerId}`). */
2401
+ function getGeoGroupId(dataPath) {
2402
+ if (typeof dataPath === 'string' && dataPath.includes('.')) {
2403
+ return dataPath.split('.').slice(0, -1).join('.');
2404
+ }
2405
+ return 'default';
2406
+ }
2407
+ /**
2408
+ * Resolve the human-readable label for a geo level from persisted hierarchy JSON.
2409
+ * Used in readonly mode when API options are not loaded.
2410
+ */
2411
+ function resolveGeoWidgetLevelLabel(values, widgetId, dataPath, geoConfig) {
2412
+ if (!dataPath || typeof dataPath !== 'string') {
2413
+ return undefined;
2414
+ }
2415
+ const stored = getWidgetValue(values, dataPath, widgetId);
2416
+ const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
2417
+ if (!Array.isArray(hierarchy)) {
2418
+ return undefined;
2419
+ }
2420
+ const levelData = hierarchy.find((l) => l.level === geoConfig.level);
2421
+ if (levelData?.level_value_mnemonic) {
2422
+ return String(levelData.level_value_mnemonic);
2423
+ }
2424
+ return undefined;
2425
+ }
2426
+ /** All registered geo widgets that are descendants of ancestorWidgetId. */
2427
+ function getGeoDescendantWidgetIds(ancestorWidgetId) {
2428
+ const descendants = [];
2429
+ for (const [childId, parentId] of geoWidgetParentRegistry.entries()) {
2430
+ if (isUpstreamGeoAncestor(ancestorWidgetId, childId, parentId)) {
2431
+ descendants.push(childId);
2432
+ }
2433
+ }
2434
+ return descendants;
2435
+ }
2139
2436
  function readStoredHierarchyLevels(values, dataPath, widgetId) {
2140
2437
  const stored = getWidgetValue(values, dataPath, widgetId);
2141
2438
  const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
@@ -2180,12 +2477,13 @@ function resetAndSeedGeoHierarchyFromValues(values, dataPath, widgetId, groupId)
2180
2477
 
2181
2478
  // Define stable empty arrays to avoid selector reference issues
2182
2479
  const EMPTY_ERRORS = [];
2183
- const EMPTY_DATA_SOURCE$1 = [];
2480
+ const EMPTY_DATA_SOURCE = [];
2184
2481
  const useBaseWidget = (options) => {
2185
2482
  const { config, dataSourceRequestHandler: propHandler, schemaData, onValueChange } = options;
2186
2483
  const dispatch = reactRedux.useDispatch();
2187
2484
  const context = useWidgetContext();
2188
2485
  const eventBus = useWidgetEventBus();
2486
+ const { translateConfig } = useWidgetTranslation();
2189
2487
  const widgetId = config['widget-id'];
2190
2488
  // Fall back to WidgetContext for dataSourceRequestHandler
2191
2489
  const dataSourceRequestHandler = propHandler || context.dataSourceRequestHandler;
@@ -2194,7 +2492,7 @@ const useBaseWidget = (options) => {
2194
2492
  const errors = reactRedux.useSelector((state) => state.widget.errors[widgetId] ?? EMPTY_ERRORS);
2195
2493
  const touched = reactRedux.useSelector((state) => state.widget.touched[widgetId] || false);
2196
2494
  const loading = reactRedux.useSelector((state) => state.widget.loading[widgetId] || false);
2197
- const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE$1);
2495
+ const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE);
2198
2496
  // Skip value handling for layout widgets (they don't store data values)
2199
2497
  // Infer layout from widget-type
2200
2498
  const isLayoutWidget = config['widget-type'] === 'layout';
@@ -2356,6 +2654,15 @@ const useBaseWidget = (options) => {
2356
2654
  }
2357
2655
  // eslint-disable-next-line react-hooks/exhaustive-deps
2358
2656
  }, [isLayoutWidget]); // Only run once on mount
2657
+ const resolveIsRequired = React.useCallback((currentValues) => {
2658
+ if (isLayoutWidget) {
2659
+ return false;
2660
+ }
2661
+ if (config['widget-readonly']) {
2662
+ return false;
2663
+ }
2664
+ return evaluateWidgetConditions(config['widget-data-options'], currentValues, config['widget-required'] ?? false).required;
2665
+ }, [config, isLayoutWidget]);
2359
2666
  // Handle value change
2360
2667
  // CRITICAL: Don't include 'values' in dependency array - it causes the callback to be recreated
2361
2668
  // every time values change, which can lead to stale closures and double dispatches
@@ -2372,13 +2679,16 @@ const useBaseWidget = (options) => {
2372
2679
  // This prevents data disappearance when switching to Edit mode and components
2373
2680
  // incorrectly clear values before options load or if handler is temporarily missing.
2374
2681
  if (newValue === '' || newValue === null || newValue === undefined) {
2375
- if (loadingRef.current) {
2376
- console.warn(`[useBaseWidget] Ignoring empty value for ${widgetId} because data source is loading`);
2377
- return;
2378
- }
2379
- if (config['widget-data-source']?.type === 'api' && dataSourceOptionsRef.current.length === 0) {
2380
- console.warn(`[useBaseWidget] Ignoring empty value for ${widgetId} because API options are empty`);
2381
- return;
2682
+ const allowEmptyClear = config.widget === 'register-lookup';
2683
+ if (!allowEmptyClear) {
2684
+ if (loadingRef.current) {
2685
+ console.warn(`[useBaseWidget] Ignoring empty value for ${widgetId} because data source is loading`);
2686
+ return;
2687
+ }
2688
+ if (config['widget-data-source']?.type === 'api' && dataSourceOptionsRef.current.length === 0) {
2689
+ console.warn(`[useBaseWidget] Ignoring empty value for ${widgetId} because API options are empty`);
2690
+ return;
2691
+ }
2382
2692
  }
2383
2693
  }
2384
2694
  // Mark that user has set a value (unless this is the default initialization)
@@ -2396,29 +2706,26 @@ const useBaseWidget = (options) => {
2396
2706
  lastDispatchedValueRef.current = newValue;
2397
2707
  dispatch(setValue({ widgetId, value: newValue }));
2398
2708
  }
2709
+ else if (config['widget-geo-config']) {
2710
+ // Geo widgets: hierarchy dataPath is managed by useGeoWidgetCascade
2711
+ getGeoDescendantWidgetIds(widgetId).forEach((descendantId) => {
2712
+ dispatch(setValue({ widgetId: descendantId, value: GEO_LEVEL_CLEARED }));
2713
+ dispatch(setDataSource({ widgetId: descendantId, data: [] }));
2714
+ });
2715
+ dispatch(setValue({ widgetId, value: newValue }));
2716
+ }
2399
2717
  else {
2400
- // Has dataPath: update both widgetId and dataPath
2401
- // CRITICAL: For geo widgets, we do NOT want to overwrite the shared hierarchy dataPath
2402
- // with a primitive value (the selected ID). The hierarchy object is managed by useGeoWidgetCascade.
2403
- if (config['widget-geo-config']) {
2404
- dispatch(setValue({ widgetId, value: newValue }));
2405
- return;
2406
- }
2407
- // For non-geo widgets, update both widgetId and dataPath
2408
- // CRITICAL: Create updated values object with newValue already set
2409
- // This prevents setWidgetValue from reading stale values
2718
+ // Non-geo widgets: update both widgetId and dataPath
2410
2719
  const currentValuesWithUpdate = {
2411
2720
  ...valuesRef.current,
2412
- [widgetId]: newValue, // Ensure widgetId has the new value
2721
+ [widgetId]: newValue,
2413
2722
  };
2414
2723
  const updatedValues = setWidgetValue(currentValuesWithUpdate, config['widget-data-path'], widgetId, newValue);
2415
- // setWidgetValue returns the complete updated structure with all existing data preserved
2416
- // Use setValues to update the entire state with deep merge
2417
2724
  dispatch(setValues(updatedValues));
2418
2725
  }
2419
2726
  // Validate if needed
2420
2727
  if (validate) {
2421
- const validationErrors = validateWidget(newValue, config['widget-data-validation'], config['widget-required']);
2728
+ const validationErrors = validateWidget(newValue, config['widget-data-validation'], resolveIsRequired(currentValues));
2422
2729
  dispatch(setError({ widgetId, errors: validationErrors }));
2423
2730
  }
2424
2731
  // Call custom onChange if provided
@@ -2437,13 +2744,12 @@ const useBaseWidget = (options) => {
2437
2744
  timestamp: Date.now(),
2438
2745
  });
2439
2746
  }
2440
- }, [config, widgetId, dispatch, onValueChange, eventBus] // Removed 'values' to prevent stale closures
2747
+ }, [config, widgetId, dispatch, onValueChange, eventBus, resolveIsRequired] // Removed 'values' to prevent stale closures
2441
2748
  );
2442
2749
  // Handle blur
2443
2750
  const handleBlur = React.useCallback(() => {
2444
2751
  dispatch(setTouched({ widgetId, touched: true }));
2445
- // Validate on blur
2446
- const validationErrors = validateWidget(currentValue, config['widget-data-validation'], config['widget-required']);
2752
+ const validationErrors = validateWidget(currentValue, config['widget-data-validation'], resolveIsRequired(valuesRef.current));
2447
2753
  dispatch(setError({ widgetId, errors: validationErrors }));
2448
2754
  // Publish widget:blur event
2449
2755
  if (eventBus) {
@@ -2454,7 +2760,7 @@ const useBaseWidget = (options) => {
2454
2760
  timestamp: Date.now(),
2455
2761
  });
2456
2762
  }
2457
- }, [currentValue, config, widgetId, dispatch, eventBus]);
2763
+ }, [currentValue, config, widgetId, dispatch, eventBus, resolveIsRequired]);
2458
2764
  // Get field value helper
2459
2765
  const getFieldValue = React.useCallback((path) => {
2460
2766
  return getWidgetValue(values, path, '');
@@ -2462,7 +2768,7 @@ const useBaseWidget = (options) => {
2462
2768
  // Conditional visibility and enablement
2463
2769
  const isVisible = React.useMemo(() => {
2464
2770
  // Layout widgets are always visible unless explicitly hidden
2465
- if (isLayoutWidget && !config['widget-data-options']?.condition) {
2771
+ if (isLayoutWidget && !hasVisibilityRules(config['widget-data-options'])) {
2466
2772
  return true;
2467
2773
  }
2468
2774
  return shouldShowWidget(config['widget-data-options'], values);
@@ -2477,6 +2783,7 @@ const useBaseWidget = (options) => {
2477
2783
  }
2478
2784
  return shouldEnableWidget(config['widget-data-options'], values);
2479
2785
  }, [config['widget-readonly'], config['widget-data-options'], values, isLayoutWidget]);
2786
+ const isRequired = React.useMemo(() => resolveIsRequired(values), [resolveIsRequired, values]);
2480
2787
  // Format value for display
2481
2788
  const formattedValue = React.useMemo(() => {
2482
2789
  if (!config['widget-data-format']) {
@@ -2507,6 +2814,8 @@ const useBaseWidget = (options) => {
2507
2814
  const apiService = dataSource?.type === 'api' ? dataSource.service : '';
2508
2815
  const apiEndpoint = dataSource?.type === 'api' ? dataSource.endpoint : '';
2509
2816
  const configKey = `${widgetId}-${isReadonly}-${dataSource?.type || 'none'}-${apiService}-${apiEndpoint}`;
2817
+ // Stable key so inline schemaData objects (e.g. dialog-table fields) don't retrigger loads every render
2818
+ const schemaDataKey = React.useMemo(() => (schemaData ? JSON.stringify(schemaData) : ''), [schemaData]);
2510
2819
  // Extract dependency value using a granular selector to prevent unnecessary re-renders
2511
2820
  // and infinite loops when other unrelated values in the state change.
2512
2821
  const dependencyValue = reactRedux.useSelector((state) => {
@@ -2523,10 +2832,9 @@ const useBaseWidget = (options) => {
2523
2832
  if (!dataSource) {
2524
2833
  return;
2525
2834
  }
2526
- // For API data sources, check if widget is readonly
2527
- // According to PRD: "Level 1 geo widgets load on widget mount or when entering edit mode"
2528
- // So we should only load API data sources when widget is NOT readonly
2529
- if (dataSource.type === 'api' && isReadonly) {
2835
+ const loadApiInReadonly = !!geoConfig ||
2836
+ ['select', 'radio', 'checkbox', 'multi-select'].includes(config.widget);
2837
+ if (dataSource.type === 'api' && isReadonly && !loadApiInReadonly) {
2530
2838
  return;
2531
2839
  }
2532
2840
  // For widgets with dependencies, check if dependency value exists
@@ -2568,6 +2876,30 @@ const useBaseWidget = (options) => {
2568
2876
  // React will call this effect again when the handler is ready
2569
2877
  return;
2570
2878
  }
2879
+ const resolveOptionKeys = () => {
2880
+ if (dataSource.type === 'static') {
2881
+ return { valueKey: undefined, labelKey: undefined };
2882
+ }
2883
+ if (geoConfig) {
2884
+ return {
2885
+ valueKey: dataSource.valueKey || 'level_value_id',
2886
+ labelKey: dataSource.labelKey || 'level_value_mnemonic',
2887
+ };
2888
+ }
2889
+ return { valueKey: dataSource.valueKey, labelKey: dataSource.labelKey };
2890
+ };
2891
+ if (dataSource.type === 'api') {
2892
+ const levelId = geoConfig?.level;
2893
+ const cached = getCachedApiDataSource(dataSource, valuesRef.current, levelId);
2894
+ if (cached) {
2895
+ const { valueKey, labelKey } = resolveOptionKeys();
2896
+ dispatch(setDataSource({
2897
+ widgetId,
2898
+ data: transformDataSourceOptions(cached, valueKey, labelKey),
2899
+ }));
2900
+ return;
2901
+ }
2902
+ }
2571
2903
  dispatch(setLoading({ widgetId, loading: true }));
2572
2904
  let data = [];
2573
2905
  if (dataSource.type === 'static') {
@@ -2580,31 +2912,13 @@ const useBaseWidget = (options) => {
2580
2912
  dispatch(setDataSource({ widgetId, data: [] }));
2581
2913
  return;
2582
2914
  }
2583
- // Extract level_id from widget-geo-config.level if available
2584
2915
  const levelId = geoConfig?.level;
2585
2916
  data = await getApiDataSource(dataSource, valuesRef.current, currentHandler, levelId);
2586
2917
  }
2587
2918
  else if (dataSource.type === 'schema') {
2588
2919
  data = getSchemaDataSource(dataSource, schemaData || {});
2589
2920
  }
2590
- // Transform to { value, label } format
2591
- // For geo widgets, default to level_value_id and level_value_mnemonic
2592
- let valueKey;
2593
- let labelKey;
2594
- if (dataSource.type === 'static') {
2595
- valueKey = undefined;
2596
- labelKey = undefined;
2597
- }
2598
- else if (geoConfig) {
2599
- // Geo widgets: default to level_value_id and level_value_mnemonic
2600
- valueKey = dataSource.valueKey || 'level_value_id';
2601
- labelKey = dataSource.labelKey || 'level_value_mnemonic';
2602
- }
2603
- else {
2604
- // Non-geo widgets: use specified keys or undefined
2605
- valueKey = dataSource.valueKey;
2606
- labelKey = dataSource.labelKey;
2607
- }
2921
+ const { valueKey, labelKey } = resolveOptionKeys();
2608
2922
  const transformed = transformDataSourceOptions(data, valueKey, labelKey);
2609
2923
  dispatch(setDataSource({ widgetId, data: transformed }));
2610
2924
  }
@@ -2619,16 +2933,25 @@ const useBaseWidget = (options) => {
2619
2933
  loadDataSource();
2620
2934
  // Use configKey and dependencyValue to ensure effect runs only when relevant state changes
2621
2935
  // eslint-disable-next-line react-hooks/exhaustive-deps
2622
- }, [configKey, dependencyValue, dataSourceRequestHandler, schemaData, widgetId, dispatch]);
2936
+ }, [configKey, dependencyValue, dataSourceRequestHandler, schemaDataKey, widgetId, dispatch]);
2937
+ const geoDisplayLabel = React.useMemo(() => {
2938
+ if (!geoConfig) {
2939
+ return undefined;
2940
+ }
2941
+ const rawLabel = resolveGeoWidgetLevelLabel(values, widgetId, config['widget-data-path'], geoConfig);
2942
+ return rawLabel ? translateConfig(rawLabel) : undefined;
2943
+ }, [values, widgetId, config, geoConfig, translateConfig]);
2623
2944
  return {
2624
2945
  widgetId,
2625
2946
  value: currentValue,
2947
+ geoDisplayLabel,
2626
2948
  formattedValue,
2627
2949
  error: errors,
2628
2950
  touched,
2629
2951
  loading,
2630
2952
  isVisible,
2631
2953
  isEnabled,
2954
+ isRequired,
2632
2955
  onChange: handleChange,
2633
2956
  onBlur: handleBlur,
2634
2957
  setError: (errors) => dispatch(setError({ widgetId, errors })),
@@ -2699,8 +3022,6 @@ const useWidgetCascade = (options) => {
2699
3022
  }, [cascadeConfig, eventBus, dataSource, widgetId, dispatch]);
2700
3023
  };
2701
3024
 
2702
- // Define stable empty array to avoid selector reference issues
2703
- const EMPTY_DATA_SOURCE = [];
2704
3025
  /**
2705
3026
  * Hook for geo widget cascade functionality
2706
3027
  * Handles geo hierarchy building and cascade behavior
@@ -2719,6 +3040,7 @@ const useGeoWidgetCascade = (options) => {
2719
3040
  const valuesRef = React.useRef(values);
2720
3041
  const handlerRef = React.useRef(dataSourceRequestHandler);
2721
3042
  const lastCascadePublishRef = React.useRef(undefined);
3043
+ const lastDirectParentValueRef = React.useRef(undefined);
2722
3044
  // Keep refs updated
2723
3045
  React.useEffect(() => {
2724
3046
  valuesRef.current = values;
@@ -2729,15 +3051,15 @@ const useGeoWidgetCascade = (options) => {
2729
3051
  ? resolveGeoWidgetLevelValue(state.widget.values, widgetId, dataPath, geoConfig)
2730
3052
  : state.widget.values[widgetId]);
2731
3053
  // Memoize selector to avoid returning new array reference
2732
- const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE);
3054
+ const allDataSources = reactRedux.useSelector((state) => state.widget.dataSources);
2733
3055
  // Register parent chain for upstream-ancestor detection (grandparent → grandchild reset)
2734
3056
  React.useEffect(() => {
2735
- if (!geoConfig) {
3057
+ if (!geoConfig || typeof dataPath !== 'string') {
2736
3058
  return;
2737
3059
  }
2738
- registerGeoWidgetParent(widgetId, geoConfig.parentWidgetId);
2739
- return () => unregisterGeoWidgetParent(widgetId);
2740
- }, [widgetId, geoConfig]);
3060
+ registerGeoWidget(widgetId, geoConfig, dataPath);
3061
+ return () => unregisterGeoWidget(widgetId);
3062
+ }, [widgetId, geoConfig, dataPath]);
2741
3063
  // Keep in-memory builder in sync with persisted hierarchy (reload, cancel→re-edit, etc.)
2742
3064
  React.useEffect(() => {
2743
3065
  if (!geoConfig || typeof dataPath !== 'string') {
@@ -2788,6 +3110,13 @@ const useGeoWidgetCascade = (options) => {
2788
3110
  event.value === null ||
2789
3111
  event.value === '' ||
2790
3112
  event.value === GEO_LEVEL_CLEARED;
3113
+ const isFirstParentEvent = lastDirectParentValueRef.current === undefined;
3114
+ const parentValueChanged = !isFirstParentEvent &&
3115
+ lastDirectParentValueRef.current !== event.value;
3116
+ lastDirectParentValueRef.current = event.value;
3117
+ if (!parentCleared && !parentValueChanged && !isFirstParentEvent) {
3118
+ return;
3119
+ }
2791
3120
  let parentValue = event.value;
2792
3121
  if (!parentCleared && (parentValue === undefined || parentValue === null)) {
2793
3122
  parentValue = currentValues[parentWidgetId];
@@ -2822,18 +3151,20 @@ const useGeoWidgetCascade = (options) => {
2822
3151
  }, [geoConfig, eventBus, dataSource, widgetId, dataPath, dispatch, groupId]);
2823
3152
  // Handle value changes to build hierarchy
2824
3153
  React.useEffect(() => {
2825
- if (!geoConfig) {
3154
+ if (!geoConfig || typeof dataPath !== 'string') {
2826
3155
  return;
2827
3156
  }
2828
- // Skip if value is undefined (it might still be loading or rehydrating)
3157
+ const { level, isLastLevel } = geoConfig;
3158
+ const groupRegistrations = getGeoWidgetRegistrationsInGroup(groupId);
3159
+ const applyGroupRebuild = () => {
3160
+ const resolveMnemonic = createGeoLevelMnemonicResolver(valuesRef.current, allDataSources);
3161
+ rebuildGeoHierarchyFromRegistrations(groupId, valuesRef.current, groupRegistrations, resolveMnemonic);
3162
+ dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
3163
+ };
2829
3164
  // ONLY clear hierarchy if the value is explicitly null or empty string (user action)
2830
3165
  if (currentValue === null || currentValue === '') {
2831
- const { level, isLastLevel } = geoConfig;
2832
3166
  geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
2833
- // If we have a dataPath, we need to update Redux with the cleared hierarchy
2834
- if (dataPath) {
2835
- dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
2836
- }
3167
+ applyGroupRebuild();
2837
3168
  if (!isLastLevel && eventBus && lastCascadePublishRef.current !== GEO_LEVEL_CLEARED) {
2838
3169
  lastCascadePublishRef.current = GEO_LEVEL_CLEARED;
2839
3170
  eventBus.publish({
@@ -2846,66 +3177,13 @@ const useGeoWidgetCascade = (options) => {
2846
3177
  return;
2847
3178
  }
2848
3179
  if (currentValue === undefined) {
2849
- return; // Skip if undefined (still initializing)
2850
- }
2851
- const { level, isLastLevel } = geoConfig;
2852
- // Check if hierarchy is already built to prevent endless loops
2853
- if (dataPath) {
2854
- const currentHierarchy = getWidgetValue(valuesRef.current, dataPath, widgetId);
2855
- // If hierarchy JSON is already set and matches current value, skip rebuilding
2856
- if (currentHierarchy && typeof currentHierarchy === 'object') {
2857
- // Check if this specific level's value matches the hierarchy
2858
- const hierarchyArray = currentHierarchy.hierarchy || currentHierarchy.geo_code_hierarchy_json?.hierarchy;
2859
- if (Array.isArray(hierarchyArray)) {
2860
- const currentLevelValue = typeof currentValue === 'object'
2861
- ? (currentValue.level_value_id || currentValue.id || currentValue.value)
2862
- : currentValue;
2863
- const levelData = hierarchyArray.find((l) => l.level === geoConfig.level);
2864
- // If this level is already correctly represented in the hierarchy, skip rebuilding
2865
- // String conversion ensures comparison works for mixed types
2866
- if (levelData && String(levelData.level_value_id) === String(currentLevelValue)) {
2867
- return;
2868
- }
2869
- }
3180
+ const hasOwnValue = Object.prototype.hasOwnProperty.call(valuesRef.current, widgetId);
3181
+ if (!hasOwnValue) {
3182
+ return;
2870
3183
  }
2871
3184
  }
2872
- // Extract level_value_id and level_value_mnemonic from current value
2873
- // The value could be the ID itself or an object with id/name
2874
- let level_value_id;
2875
- let level_value_mnemonic;
2876
- if (typeof currentValue === 'string' || typeof currentValue === 'number') {
2877
- // Value is just the ID, need to find mnemonic from data source
2878
- level_value_id = String(currentValue);
2879
- // Try to get mnemonic from data source options
2880
- const option = dataSourceOptions.find((opt) => opt.value === currentValue);
2881
- level_value_mnemonic = option?.label || String(currentValue);
2882
- }
2883
- else if (currentValue && typeof currentValue === 'object') {
2884
- level_value_id = currentValue.level_value_id || currentValue.id || currentValue.value;
2885
- level_value_mnemonic = currentValue.level_value_mnemonic || currentValue.name || currentValue.label;
2886
- }
2887
- else {
2888
- return;
2889
- }
2890
- // When a widget's own value changes, remove this level and all below from hierarchy first
2891
- geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
2892
- // Add level to hierarchy
2893
- geoHierarchyBuilder.addLevel(level, level_value_id, level_value_mnemonic, groupId);
2894
- // Build and store hierarchy JSON on every change
2895
- if (dataPath && geoHierarchyBuilder.buildHierarchyJson(groupId)) {
2896
- dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
2897
- }
2898
- // Notify descendants when this level changes via hierarchy/rehydration (handleChange may not run).
2899
- if (!isLastLevel && eventBus && lastCascadePublishRef.current !== level_value_id) {
2900
- lastCascadePublishRef.current = level_value_id;
2901
- eventBus.publish({
2902
- type: 'widget:change',
2903
- widgetId,
2904
- value: level_value_id,
2905
- timestamp: Date.now(),
2906
- });
2907
- }
2908
- }, [geoConfig, currentValue, widgetId, dataPath, dispatch, dataSourceOptions, eventBus, groupId]);
3185
+ applyGroupRebuild();
3186
+ }, [geoConfig, currentValue, widgetId, dataPath, dispatch, allDataSources, groupId, eventBus]);
2909
3187
  };
2910
3188
 
2911
3189
  class WidgetRegistry {
@@ -3030,98 +3308,6 @@ const WidgetRenderer = ({ config, dataSourceRequestHandler: propDataSourceReques
3030
3308
  return (jsxRuntimeExports.jsx("div", { className: "widget-container", "data-widget-id": widgetContext.widgetId, style: { marginBottom: 0 }, children: widgetRegistry.render(config, widgetContext, defaultComponent) }));
3031
3309
  };
3032
3310
 
3033
- /**
3034
- * Custom hook for widget translations
3035
- * Provides translation function with widget-specific namespace and fallback support
3036
- */
3037
- const useWidgetTranslation = () => {
3038
- const { translate: translateFunction } = useWidgetContext();
3039
- /**
3040
- * Translate a key with flexible namespace support
3041
- * Supports translation keys in various formats and direct strings
3042
- *
3043
- * Translation key formats supported:
3044
- * - "widgets:common.addItem" - Namespaced key (for widget-specific translations)
3045
- * - "Name" - Direct string (will be looked up in flat translation structure)
3046
- * - "sections.personalDetails" - Nested key (for backward compatibility)
3047
- *
3048
- * With flat translation structure, direct strings like "Name" are automatically
3049
- * translated by looking them up in the translation resources.
3050
- *
3051
- * @param keyOrString - Translation key (e.g., "widgets:common.addItem") or direct string (e.g., "Name")
3052
- * @param options - Translation options (interpolation values, default value, etc.)
3053
- * @returns Translated string or original string if translation not found
3054
- */
3055
- const translate = (keyOrString, options) => {
3056
- if (!keyOrString) {
3057
- return options?.defaultValue || '';
3058
- }
3059
- // Use the provided translation function or fallback to the key
3060
- if (translateFunction) {
3061
- return translateFunction(keyOrString, options) || options?.defaultValue || keyOrString;
3062
- }
3063
- // Fallback to key if no translation function available
3064
- return options?.defaultValue || keyOrString;
3065
- };
3066
- /**
3067
- * Translate widget config property
3068
- * Attempts to translate the value, but if translation is not found,
3069
- * returns the original value as-is (graceful fallback)
3070
- *
3071
- * This function will:
3072
- * - Try to translate any string value
3073
- * - If translation exists, use the translated value
3074
- * - If translation doesn't exist (returns same value or throws), use original value
3075
- * - This prevents errors when literal strings like "XXXX-XXXX-XXXX" are used
3076
- */
3077
- const translateConfig = (value, fallback) => {
3078
- if (!value) {
3079
- return fallback || '';
3080
- }
3081
- // Try to translate the value
3082
- if (translateFunction) {
3083
- try {
3084
- // Pass defaultValue to ensure we get the original value if translation fails
3085
- const translated = translateFunction(value, { defaultValue: value });
3086
- // If translation returns empty, null, undefined, or the exact same value,
3087
- // it means no translation was found - return the original value
3088
- if (!translated || translated === value) {
3089
- return value;
3090
- }
3091
- // Translation found, return it
3092
- return translated;
3093
- }
3094
- catch (error) {
3095
- // If translation throws an error (e.g., missing key warning), return original value
3096
- return value;
3097
- }
3098
- }
3099
- // No translation function available, return value as-is
3100
- return value;
3101
- };
3102
- // No need of this getLanguage and changeLanguage functions
3103
- /**
3104
- * Get current language
3105
- */
3106
- // const getLanguage = (): string => {
3107
- // return i18n.language || 'en';
3108
- // };
3109
- /**
3110
- * Change language
3111
- */
3112
- // const changeLanguage = (lng: string): Promise<void> => {
3113
- // return i18n.changeLanguage(lng).then(() => undefined);
3114
- // };
3115
- return {
3116
- t: translate,
3117
- translate,
3118
- translateConfig,
3119
- // getLanguage,
3120
- // changeLanguage,
3121
- // i18n: null,
3122
- };
3123
- };
3124
-
3125
3311
  /**
3126
3312
  * Renders a panel with its nested panels or widgets
3127
3313
  *
@@ -3240,6 +3426,16 @@ const PanelRenderer = ({ panel, dataSourceRequestHandler, schemaData, onValueCha
3240
3426
  return (jsxRuntimeExports.jsx("div", { className: `panel panel-${orientation}`, "data-panel-id": panel['panel-id'], style: orientation === 'horizontal' ? { width: '100%' } : {}, children: content }));
3241
3427
  };
3242
3428
 
3429
+ /**
3430
+ * Field label: long text truncates with ellipsis; required asterisk always stays visible.
3431
+ */
3432
+ const WidgetFieldLabel = ({ label, required = false, className = '', title, }) => {
3433
+ const { translateConfig } = useWidgetTranslation();
3434
+ const translatedLabel = translateConfig(label);
3435
+ const tooltip = title !== undefined ? translateConfig(title) : translatedLabel;
3436
+ return (jsxRuntimeExports.jsxs("label", { className: `flex items-baseline min-w-0 max-w-full ${className}`, style: { fontFamily: 'Roboto, sans-serif' }, title: tooltip, children: [jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate", children: translatedLabel }), required && jsxRuntimeExports.jsx("span", { className: "ml-1 shrink-0 text-red-500", children: "*" })] }));
3437
+ };
3438
+
3243
3439
  /**
3244
3440
  * Utility functions for file preview functionality
3245
3441
  */
@@ -3283,7 +3479,11 @@ const canPreviewInWeb = (file) => {
3283
3479
  return previewableExtensions.includes(extension.toLowerCase());
3284
3480
  };
3285
3481
 
3286
- var img$f = "data:image/png;base64,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";
3482
+ var img$h = "data:image/png;base64,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";
3483
+
3484
+ var img$g = "data:image/png;base64,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";
3485
+
3486
+ var img$f = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAACAKADAAQAAAABAAACAAAAAAAL+LWFAAAkvUlEQVR4Ae3d344sVb0H8I1GuMFofAD5p95443ucGwHJifgg8g7wDpoYJecCvOGEIHAFr2ACMeobqES4OCGBsxZ7L2emd/f8urtqVa0/n04qvWemu2rVp35rfX/Tu2fmwQM3AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBA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AfCGPyVNIBYYqQnIa5cbAQILBF5Kz+29AfCd/4IC8NTpBEZpAl6c7so5YQIrC+T3aXyStl6bAN/5r1wQdjeFQO9NQF6zvMdsilJ1krUFcifdYwPgO//alWH/Iwv03AT8fOQL49wIbC3wbjpgT02A8N+6QhxvRIEem4D3R7wQzonAngLPp4Pnvw/QQxPgZf89K8WxRxPoqQnIa1Req9wIEFhZ4JW0v9YbAN/5r3zR7Y5AEuilCXjV1SJAoJ7A62nXrTYBvvOvd93tmUDrTUBem9wIEKgo8ETa92/S1loT4Dv/ihfdrgk8Emi1Cfh9Gp93/StTAhsI5EXgd2lrpQnIY8ljciNAoL6A+V/f2BEINC2QXwl4I217NwH5Zb88FjcCBLYTMP+3s3YkAs0K5N8U+I+0bd0IfJaO+ctmVQyMwBwC5v8c19lZEjgp8EL6Sv7Z262agPxXCv2oz8nL4QsENhUw/zfldjACbQrk7wY+TVutRiD/ek+/37vNa29UBMx/NUBgcoH8TtyX0/Zx2tb4U8J5Hx+lLS8u3uWbENwINCxg/jd8cQyNwJYCz6aDvZa2D9P2RdrOfWUgP/aDtP06bc+kzY0Agf4Enk1DNv/7u26bjdi7tzej3v1AT6YR/DRtP0rbc2n7QdqeTlu+fZ62/EbCv6ftL2n7c9q+TJsbAQJjCJj/Y1xHZ0GAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgssD/A1hw9f23AMmGAAAAAElFTkSuQmCC";
3287
3487
 
3288
3488
  var img$e = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAkCAYAAACe0YppAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAHqADAAQAAAABAAAAJAAAAAAh0JciAAACrUlEQVRYCcWXPW8TQRCG31kbpNBChGiiRJQ0tFDggPgBtKGhJgEJUGxDFCmJUBKwDUoV2jRxS2NEhZCgAPELKBAhIPFRpKIwUXIe3vFHFJzbs2zWupHWu7e7M8/OenbuVkDReUzoLjbZvGDP/ysiWJQSlpLsiN7HOBp4rco6oBC+Svicz2QWERYULSjh605Q3dvHnk/B138sg1EV1DrjtPVAC9j1eS6NPD5x8lko3rgKch3FfmvbOY2w1a3n89xxlWdsMuvP3UqDPhO2xPLF9NueL3Tbct0dIZ4jJdTh8iH4Irf9H/hQwLZ4edSCs7ltz/Tc4CvWNhka2IwbXDKYZLMDt4Brep61CUFE8Jt26iwj9KbcKGDW7GrDfnGi+csf8zwqoh7MY1nFjhLYBpziKTl3UIDRDthqp5gJ5zENZsrMCXlscQE3DoMO2sJ8wURFr08GBRtAythgZeWIRAVsSDtZBdvqI5QeHamBE7c6yqPKJND/G0sZvIqXmQpmfI57wVrEGI/CFINhIOGCp3lml/mS+B5nwAuWx/iqs5hnDr8ap9ijT7noF+5JPNR0vWAblAqWWVkJLqkFV2rgxK1mVG8ySC4Oss/NqC5j2qfrBdf5RSERrg8c1cBNvYOHsoYfcXAveISvNHpcZIrLxSkm9rXO8SvngZquF2yDTPolVlaCS2rBlRo4cav56fscgvNJ+8wYqDEt3k6aEzfmBVtU82P/Wq+oZiq/pfdQkqf4Fgfw9XnBFtXM1XeZq73nmGPK68871yfUFuMF2yBz9RorK8ElteDiHY2blYI4/ks7xuUCxofNJ2OizfiZZVTW2GGfKJNMkc9cFlUu5k/QRQiOYx9TfHFcMrtkvhWdw2l2fmDnWFCY39i2XWucrOAXb1A5ruKjf26wkfeEXrE71V+iV9IhdJQEvwAAAABJRU5ErkJggg==";
3289
3489
 
@@ -3585,7 +3785,7 @@ const deserializeValue = (value) => {
3585
3785
  };
3586
3786
 
3587
3787
  const FileInputWidget = ({ config }) => {
3588
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
3788
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
3589
3789
  const { translate, translateConfig } = useWidgetTranslation();
3590
3790
  const accept = widgetConfig['widget-data-options']?.accept;
3591
3791
  const multiple = widgetConfig['widget-data-options']?.multiple || false;
@@ -3825,7 +4025,7 @@ const FileInputWidget = ({ config }) => {
3825
4025
  setPreviewFile(null);
3826
4026
  } })] }));
3827
4027
  }
3828
- return (jsxRuntimeExports.jsxs("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: "flex flex-col sm:flex-row sm:items-center gap-2 sm:space-x-4", children: [jsxRuntimeExports.jsxs("label", { className: `cursor-pointer inline-flex items-center justify-between gap-2 border border-gray-300 shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 ${!isEnabled
4028
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px]", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center gap-2 sm:space-x-4", children: [jsxRuntimeExports.jsxs("label", { className: `cursor-pointer inline-flex items-center justify-between gap-2 border border-gray-300 shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 ${!isEnabled
3829
4029
  ? 'opacity-50 cursor-not-allowed'
3830
4030
  : ''}`, style: {
3831
4031
  width: '100%',
@@ -3886,6 +4086,13 @@ const namespaceWidgetConfig = (widgetConfig, namespace) => {
3886
4086
  if (namespaced['widget-data-path']) {
3887
4087
  namespaced['widget-data-path'] = namespaceDataPath(namespaced['widget-data-path'], namespace);
3888
4088
  }
4089
+ // Namespace geo parent references so cascade events match namespaced widget-id
4090
+ if (namespaced['widget-geo-config']?.parentWidgetId) {
4091
+ namespaced['widget-geo-config'] = {
4092
+ ...namespaced['widget-geo-config'],
4093
+ parentWidgetId: `${namespace}__${namespaced['widget-geo-config'].parentWidgetId}`,
4094
+ };
4095
+ }
3889
4096
  // Recursively namespace nested widgets (for layout widgets)
3890
4097
  if (namespaced.widgets && Array.isArray(namespaced.widgets)) {
3891
4098
  namespaced.widgets = namespaced.widgets.map((widget) => namespaceWidgetConfig(widget, namespace));
@@ -4090,6 +4297,9 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
4090
4297
  const isVisible = shouldShowWidget(widget['widget-data-options'], currentSchemaData);
4091
4298
  if (!isVisible)
4092
4299
  continue;
4300
+ const isEnabled = shouldEnableWidget(widget['widget-data-options'], currentSchemaData);
4301
+ if (!isEnabled)
4302
+ continue;
4093
4303
  const widgetId = widget['widget-id'];
4094
4304
  if (isTableLikeWidget(widget)) {
4095
4305
  const tableValid = validateTableLikeWidget(widget, currentSchemaData, dispatch, skipRequired);
@@ -4099,7 +4309,8 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
4099
4309
  continue;
4100
4310
  }
4101
4311
  const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
4102
- const errors = validateWidget(value, widget['widget-data-validation'], widget['widget-required'], skipRequired);
4312
+ const isRequired = shouldRequireWidget(widget['widget-data-options'], currentSchemaData, widget['widget-required'] ?? false);
4313
+ const errors = validateWidget(value, widget['widget-data-validation'], isRequired, skipRequired);
4103
4314
  if (errors.length > 0) {
4104
4315
  isValid = false;
4105
4316
  dispatch(setTouched({ widgetId, touched: true }));
@@ -4132,6 +4343,108 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
4132
4343
  return isValid;
4133
4344
  };
4134
4345
 
4346
+ const cloneValue = (value) => {
4347
+ if (value === undefined) {
4348
+ return undefined;
4349
+ }
4350
+ try {
4351
+ return structuredClone(value);
4352
+ }
4353
+ catch {
4354
+ return JSON.parse(JSON.stringify(value));
4355
+ }
4356
+ };
4357
+ const resolveNamespacedWidgetId = (widgetId, namespace) => namespace ? `${namespace}__${widgetId}` : widgetId;
4358
+ const resolveStoreDataPath = (dataPath, namespace) => {
4359
+ if (!dataPath) {
4360
+ return dataPath;
4361
+ }
4362
+ if (!namespace) {
4363
+ return dataPath;
4364
+ }
4365
+ if (typeof dataPath === 'string') {
4366
+ return `${namespace}.${dataPath}`;
4367
+ }
4368
+ return Object.fromEntries(Object.entries(dataPath).map(([key, path]) => [key, `${namespace}.${path}`]));
4369
+ };
4370
+ /**
4371
+ * Capture Redux widget values for a section at edit entry.
4372
+ * Used to restore exact pre-edit state on Cancel (schemaData may be stale or shared with Redux).
4373
+ */
4374
+ function captureSectionEditSnapshot(values, section, options) {
4375
+ const { namespace, sectionId, supportingDocuments = [] } = options ?? {};
4376
+ const dataPaths = [];
4377
+ const processedPaths = new Set();
4378
+ const widgetIds = {};
4379
+ const addPath = (path) => {
4380
+ if (!path || processedPaths.has(path)) {
4381
+ return;
4382
+ }
4383
+ processedPaths.add(path);
4384
+ dataPaths.push({
4385
+ path,
4386
+ value: cloneValue(getValueByPath(values, path)),
4387
+ });
4388
+ if (path.endsWith('.geo_code_hierarchy_json')) {
4389
+ const prefix = path.slice(0, -'.geo_code_hierarchy_json'.length);
4390
+ addPath(`${prefix}.geo_lowest_level_value_id`);
4391
+ }
4392
+ };
4393
+ collectWidgets(section.panels).forEach((widget) => {
4394
+ const widgetId = resolveNamespacedWidgetId(widget['widget-id'], namespace);
4395
+ const storeDataPath = resolveStoreDataPath(widget['widget-data-path'], namespace);
4396
+ if (Object.prototype.hasOwnProperty.call(values, widgetId)) {
4397
+ widgetIds[widgetId] = { present: true, value: cloneValue(values[widgetId]) };
4398
+ }
4399
+ else {
4400
+ widgetIds[widgetId] = { present: false };
4401
+ }
4402
+ if (typeof storeDataPath === 'string') {
4403
+ addPath(storeDataPath);
4404
+ }
4405
+ else if (storeDataPath && typeof storeDataPath === 'object') {
4406
+ Object.values(storeDataPath).forEach((path) => {
4407
+ if (typeof path === 'string') {
4408
+ addPath(path);
4409
+ }
4410
+ });
4411
+ }
4412
+ });
4413
+ supportingDocuments.forEach((doc, index) => {
4414
+ const widgetId = `supporting-doc-${sectionId ?? 'section'}-${index}`;
4415
+ const storeDataPath = namespace && doc['document-data-path']
4416
+ ? `${namespace}.${doc['document-data-path']}`
4417
+ : doc['document-data-path'];
4418
+ if (Object.prototype.hasOwnProperty.call(values, widgetId)) {
4419
+ widgetIds[widgetId] = { present: true, value: cloneValue(values[widgetId]) };
4420
+ }
4421
+ else {
4422
+ widgetIds[widgetId] = { present: false };
4423
+ }
4424
+ if (typeof storeDataPath === 'string') {
4425
+ addPath(storeDataPath);
4426
+ }
4427
+ });
4428
+ return { dataPaths, widgetIds };
4429
+ }
4430
+ /** Apply a section edit snapshot back onto the full Redux values object. */
4431
+ function applySectionEditSnapshot(currentValues, snapshot) {
4432
+ let result = currentValues;
4433
+ for (const { path, value } of snapshot.dataPaths) {
4434
+ result = setValueByPath(result, path, cloneValue(value));
4435
+ }
4436
+ for (const [widgetId, entry] of Object.entries(snapshot.widgetIds)) {
4437
+ if (entry.present) {
4438
+ result = { ...result, [widgetId]: cloneValue(entry.value) };
4439
+ }
4440
+ else {
4441
+ const { [widgetId]: _removed, ...rest } = result;
4442
+ result = rest;
4443
+ }
4444
+ }
4445
+ return result;
4446
+ }
4447
+
4135
4448
  /** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
4136
4449
  const READONLY_VALUE_ROW_ROOT_CLASSES = [
4137
4450
  'TextDisplayWidget',
@@ -4343,6 +4656,8 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4343
4656
  }, [forceExitEdit]); // eslint-disable-line react-hooks/exhaustive-deps
4344
4657
  const [isDocumentsExpanded, setIsDocumentsExpanded] = React.useState(true);
4345
4658
  const sectionRef = React.useRef(null);
4659
+ const baselineSnapshotRef = React.useRef(null);
4660
+ const editEntrySnapshotRef = React.useRef(null);
4346
4661
  const [sectionHeight, setSectionHeight] = React.useState(null);
4347
4662
  const [editSectionPosition, setEditSectionPosition] = React.useState(null);
4348
4663
  // Capture section position when entering edit mode and update on scroll
@@ -4407,6 +4722,18 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4407
4722
  panels: makePanelsEditable(sectionToRender.panels, widgetsEditable),
4408
4723
  };
4409
4724
  }, [sectionToRender, widgetsEditable]);
4725
+ const effectiveHideEditButton = hideEditButton ||
4726
+ section['section-hide-edit-button'] === true ||
4727
+ !collectWidgets(section.panels || []).some((w) => section['section-editable'] === true || w['widget-readonly'] !== true);
4728
+ const captureEditEntrySnapshot = React.useCallback(() => {
4729
+ const currentValues = store.getState().widget.values;
4730
+ const supportingDocuments = section['section-supporting-documents'] || [];
4731
+ editEntrySnapshotRef.current = captureSectionEditSnapshot(currentValues, section, {
4732
+ namespace,
4733
+ sectionId,
4734
+ supportingDocuments: hasSupportingDocuments ? supportingDocuments : [],
4735
+ });
4736
+ }, [store, section, namespace, sectionId, hasSupportingDocuments]);
4410
4737
  // Handle edit button click
4411
4738
  const handleEdit = () => {
4412
4739
  // Capture height BEFORE entering edit mode to preserve space
@@ -4414,6 +4741,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4414
4741
  const height = sectionRef.current.offsetHeight;
4415
4742
  setSectionHeight(height);
4416
4743
  }
4744
+ captureEditEntrySnapshot();
4417
4745
  setIsEditMode(true);
4418
4746
  onEditModeChange?.(originalSectionId, true);
4419
4747
  };
@@ -4588,8 +4916,6 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4588
4916
  }
4589
4917
  return { records, files };
4590
4918
  }, [originalSection, hasSupportingDocuments]);
4591
- // Capture baseline when entering edit mode (used for isDirty comparison)
4592
- const baselineSnapshotRef = React.useRef(null);
4593
4919
  // IntakeForm only: increment when baseline is updated after save - forces badge to update (refs don't trigger re-renders)
4594
4920
  const [intakeFormBaselineTrigger, setIntakeFormBaselineTrigger] = React.useState(0);
4595
4921
  // IntakeForm: treat as edit mode for dirty tracking when isDraft. RegistryView: use isEditMode.
@@ -4607,6 +4933,9 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4607
4933
  // Set baseline when entering edit mode; clear when leaving (baseline captured only on entry)
4608
4934
  React.useEffect(() => {
4609
4935
  if (effectiveEditModeForDirty) {
4936
+ if (!editEntrySnapshotRef.current) {
4937
+ captureEditEntrySnapshot();
4938
+ }
4610
4939
  const oldSchemaData = schemaData || contextSchemaData || {};
4611
4940
  if (namespace) {
4612
4941
  const namespacedSchema = getValueByPath(oldSchemaData, namespace);
@@ -4615,11 +4944,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4615
4944
  : buildSectionSnapshot(oldSchemaData);
4616
4945
  }
4617
4946
  else {
4618
- baselineSnapshotRef.current = buildSectionSnapshot(oldSchemaData);
4947
+ baselineSnapshotRef.current = buildSectionSnapshot(store.getState().widget.values, namespace);
4619
4948
  }
4620
4949
  }
4621
4950
  else {
4622
4951
  baselineSnapshotRef.current = null;
4952
+ editEntrySnapshotRef.current = null;
4623
4953
  onSectionDirtyChange?.(sectionId, false);
4624
4954
  }
4625
4955
  // eslint-disable-next-line react-hooks/exhaustive-deps -- baseline must be captured only when effectiveEditModeForDirty toggles
@@ -4645,56 +4975,103 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4645
4975
  // and handleCancel.
4646
4976
  const revertToOriginalValues = React.useCallback(() => {
4647
4977
  const sectionWidgets = collectWidgets(originalSection.panels);
4648
- const oldSchemaData = schemaData || contextSchemaData;
4649
4978
  const currentStoreValues = store.getState().widget.values;
4979
+ const snapshot = editEntrySnapshotRef.current;
4650
4980
  let newStoreValues = currentStoreValues;
4651
- sectionWidgets.forEach(widget => {
4652
- const originalWidgetId = widget['widget-id'];
4653
- const namespacedWidgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
4654
- const widgetId = namespacedWidgetId;
4655
- const originalDataPath = widget['widget-data-path'];
4656
- const storeDataPath = namespace && originalDataPath
4657
- ? (typeof originalDataPath === 'string'
4658
- ? `${namespace}.${originalDataPath}`
4659
- : Object.fromEntries(Object.entries(originalDataPath).map(([key, path]) => [key, `${namespace}.${path}`])))
4660
- : originalDataPath;
4661
- if (widgetId && originalDataPath) {
4662
- let oldValue;
4663
- if (typeof originalDataPath === 'object') {
4664
- oldValue = {};
4665
- Object.entries(originalDataPath).forEach(([key, path]) => {
4666
- if (typeof path === 'string') {
4667
- oldValue[key] = getValueByPath(oldSchemaData, path);
4981
+ if (snapshot) {
4982
+ newStoreValues = applySectionEditSnapshot(currentStoreValues, snapshot);
4983
+ }
4984
+ else {
4985
+ const oldSchemaData = schemaData || contextSchemaData;
4986
+ const processedGeoGroups = new Set();
4987
+ sectionWidgets.forEach((widget) => {
4988
+ const originalWidgetId = widget['widget-id'];
4989
+ const namespacedWidgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
4990
+ const widgetId = namespacedWidgetId;
4991
+ const originalDataPath = widget['widget-data-path'];
4992
+ const storeDataPath = namespace && originalDataPath
4993
+ ? (typeof originalDataPath === 'string'
4994
+ ? `${namespace}.${originalDataPath}`
4995
+ : Object.fromEntries(Object.entries(originalDataPath).map(([key, path]) => [key, `${namespace}.${path}`])))
4996
+ : originalDataPath;
4997
+ const geoConfig = widget['widget-geo-config'];
4998
+ if (widgetId && originalDataPath) {
4999
+ let oldValue;
5000
+ if (typeof originalDataPath === 'object') {
5001
+ oldValue = {};
5002
+ Object.entries(originalDataPath).forEach(([key, path]) => {
5003
+ if (typeof path === 'string') {
5004
+ oldValue[key] = getValueByPath(oldSchemaData, path);
5005
+ }
5006
+ });
5007
+ }
5008
+ else if (typeof originalDataPath === 'string') {
5009
+ oldValue = getValueByPath(oldSchemaData, originalDataPath);
5010
+ }
5011
+ if (oldValue !== undefined) {
5012
+ newStoreValues = setWidgetValue(newStoreValues, storeDataPath, widgetId, oldValue);
5013
+ if (geoConfig && typeof storeDataPath === 'string') {
5014
+ const groupId = getGeoGroupId(storeDataPath);
5015
+ const levelValue = resolveGeoWidgetLevelValue(newStoreValues, widgetId, storeDataPath, geoConfig);
5016
+ if (levelValue !== undefined && levelValue !== null && levelValue !== '') {
5017
+ newStoreValues = { ...newStoreValues, [widgetId]: levelValue };
5018
+ }
5019
+ else {
5020
+ const { [widgetId]: _removed, ...rest } = newStoreValues;
5021
+ newStoreValues = rest;
5022
+ }
5023
+ if (!processedGeoGroups.has(groupId)) {
5024
+ resetAndSeedGeoHierarchyFromValues(newStoreValues, storeDataPath, widgetId, groupId);
5025
+ processedGeoGroups.add(groupId);
5026
+ }
5027
+ if (geoConfig.parentWidgetId) {
5028
+ dispatch(setDataSource({ widgetId, data: [] }));
5029
+ }
4668
5030
  }
4669
- });
4670
- }
4671
- else if (typeof originalDataPath === 'string') {
4672
- oldValue = getValueByPath(oldSchemaData, originalDataPath);
5031
+ else {
5032
+ newStoreValues = { ...newStoreValues, [widgetId]: oldValue };
5033
+ }
5034
+ }
4673
5035
  }
4674
- if (oldValue !== undefined) {
5036
+ });
5037
+ if (hasSupportingDocuments) {
5038
+ const originalSupportingDocuments = originalSection['section-supporting-documents'] || [];
5039
+ originalSupportingDocuments.forEach((doc, index) => {
5040
+ const widgetId = `supporting-doc-${sectionId}-${index}`;
5041
+ const originalDataPath = doc['document-data-path'];
5042
+ const storeDataPath = namespace && originalDataPath
5043
+ ? `${namespace}.${originalDataPath}`
5044
+ : originalDataPath;
5045
+ const oldValue = getValueByPath(oldSchemaData, originalDataPath);
4675
5046
  newStoreValues = setWidgetValue(newStoreValues, storeDataPath, widgetId, oldValue);
4676
- // Also revert the widgetId-based entry — useBaseWidget.handleChange
4677
- // sets values[widgetId] during editing, and useBaseWidget.currentValue
4678
- // reads values[widgetId] first before falling through to the dataPath.
4679
- newStoreValues = { ...newStoreValues, [widgetId]: oldValue };
4680
- }
5047
+ });
4681
5048
  }
4682
- });
4683
- if (hasSupportingDocuments) {
4684
- const originalSupportingDocuments = originalSection['section-supporting-documents'] || [];
4685
- originalSupportingDocuments.forEach((doc, index) => {
4686
- const widgetId = `supporting-doc-${sectionId}-${index}`;
4687
- const originalDataPath = doc['document-data-path'];
4688
- const storeDataPath = namespace && originalDataPath
4689
- ? `${namespace}.${originalDataPath}`
4690
- : originalDataPath;
4691
- const oldValue = getValueByPath(oldSchemaData, originalDataPath);
4692
- newStoreValues = setWidgetValue(newStoreValues, storeDataPath, widgetId, oldValue);
4693
- });
4694
- }
4695
- if (newStoreValues !== currentStoreValues) {
4696
- dispatch(setValues(newStoreValues));
4697
5049
  }
5050
+ const processedGeoGroups = new Set();
5051
+ sectionWidgets.forEach((widget) => {
5052
+ const geoConfig = widget['widget-geo-config'];
5053
+ if (!geoConfig) {
5054
+ return;
5055
+ }
5056
+ const originalWidgetId = widget['widget-id'];
5057
+ const widgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
5058
+ const originalDataPath = widget['widget-data-path'];
5059
+ const storeDataPath = namespace && typeof originalDataPath === 'string'
5060
+ ? `${namespace}.${originalDataPath}`
5061
+ : originalDataPath;
5062
+ if (typeof storeDataPath !== 'string') {
5063
+ return;
5064
+ }
5065
+ const groupId = getGeoGroupId(storeDataPath);
5066
+ if (!processedGeoGroups.has(groupId)) {
5067
+ resetAndSeedGeoHierarchyFromValues(newStoreValues, storeDataPath, widgetId, groupId);
5068
+ processedGeoGroups.add(groupId);
5069
+ }
5070
+ if (geoConfig.parentWidgetId) {
5071
+ dispatch(setDataSource({ widgetId, data: [] }));
5072
+ }
5073
+ });
5074
+ dispatch(setValues(newStoreValues));
4698
5075
  }, [originalSection, schemaData, contextSchemaData, store, namespace, hasSupportingDocuments, sectionId, dispatch]);
4699
5076
  // Handle save button click
4700
5077
  const handleSave = async () => {
@@ -4708,7 +5085,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4708
5085
  // This ensures we use the original widget IDs and data paths
4709
5086
  const sectionWidgets = collectWidgets(originalSection.panels);
4710
5087
  const currentState = store.getState().widget;
4711
- const currentSchemaData = currentState.values || {};
5088
+ let currentSchemaData = currentState.values || {};
5089
+ const geoRegistrations = collectGeoWidgetRegistrationsFromWidgets(sectionWidgets, namespace);
5090
+ if (geoRegistrations.length > 0) {
5091
+ currentSchemaData = reconcileGeoHierarchiesInValues(currentSchemaData, geoRegistrations, currentState.dataSources || {});
5092
+ dispatch(setValues(currentSchemaData));
5093
+ }
4712
5094
  const isSectionValid = sectionValidate(originalSection, currentSchemaData, dispatch, true);
4713
5095
  if (!isSectionValid) {
4714
5096
  return;
@@ -4774,7 +5156,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4774
5156
  if (isDraft !== false && store && onSectionSave) {
4775
5157
  const sectionWidgets = collectWidgets(originalSection.panels);
4776
5158
  const currentState = store.getState().widget;
4777
- const currentSchemaData = currentState.values || {};
5159
+ let currentSchemaData = currentState.values || {};
5160
+ const geoRegistrations = collectGeoWidgetRegistrationsFromWidgets(sectionWidgets, namespace);
5161
+ if (geoRegistrations.length > 0) {
5162
+ currentSchemaData = reconcileGeoHierarchiesInValues(currentSchemaData, geoRegistrations, currentState.dataSources || {});
5163
+ dispatch(setValues(currentSchemaData));
5164
+ }
4778
5165
  const isSectionValid = sectionValidate(originalSection, currentSchemaData, dispatch, true);
4779
5166
  if (!isSectionValid)
4780
5167
  return;
@@ -5190,7 +5577,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
5190
5577
  color: changeRequestType === 'new' ? 'var(--owt-color-bg, #FFFFFF)' : 'var(--owt-color-error, #B91C1C)',
5191
5578
  whiteSpace: 'nowrap',
5192
5579
  boxShadow: changeRequestType === 'new' ? '0 2px 4px rgba(40, 167, 69, 0.3)' : 'none',
5193
- }, children: changeRequestType === 'new' ? 'New' : 'Old' }))] })), jsxRuntimeExports.jsxs("div", { id: gridId, className: "section-panels", style: mode === 'RegistryView' && hideEditButton ? { paddingBottom: '30px' } : {}, children: [editableSection.panels.map((panel, index) => (jsxRuntimeExports.jsx("div", { className: "panel-wrapper", children: jsxRuntimeExports.jsx(PanelRenderer, { panel: panel, dataSourceRequestHandler: dataSourceRequestHandler, schemaData: namespacedSchemaData, onValueChange: onValueChange }) }, panel['panel-id'] || `section-panel-${index}`))), mode === 'CRView' && crViewData && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("hr", { className: "w-full", style: { height: '1px', marginTop: '20px', marginBottom: '0px', border: 'none', backgroundColor: 'var(--owt-color-border, #C4C4C4)' } }), jsxRuntimeExports.jsxs("div", { className: "cr-view-container", style: {
5580
+ }, children: changeRequestType === 'new' ? 'New' : 'Old' }))] })), jsxRuntimeExports.jsxs("div", { id: gridId, className: "section-panels", style: mode === 'RegistryView' && effectiveHideEditButton ? { paddingBottom: '30px' } : {}, children: [editableSection.panels.map((panel, index) => (jsxRuntimeExports.jsx("div", { className: "panel-wrapper", children: jsxRuntimeExports.jsx(PanelRenderer, { panel: panel, dataSourceRequestHandler: dataSourceRequestHandler, schemaData: namespacedSchemaData, onValueChange: onValueChange }) }, panel['panel-id'] || `section-panel-${index}`))), mode === 'CRView' && crViewData && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("hr", { className: "w-full", style: { height: '1px', marginTop: '20px', marginBottom: '0px', border: 'none', backgroundColor: 'var(--owt-color-border, #C4C4C4)' } }), jsxRuntimeExports.jsxs("div", { className: "cr-view-container", style: {
5194
5581
  marginTop: '20px',
5195
5582
  paddingBottom: '30px',
5196
5583
  display: 'flex',
@@ -5238,7 +5625,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
5238
5625
  fontSize: '14px',
5239
5626
  color: 'var(--owt-color-text, #011627)',
5240
5627
  fontWeight: 'normal',
5241
- }, children: crViewData.approvedDate }))] })] })] })), mode === 'RegistryView' && !hideEditButton && (jsxRuntimeExports.jsx("hr", { className: "w-full", style: { height: '1px', marginTop: !isEditMode ? '10px' : 0, marginBottom: '14px', border: 'none', backgroundColor: 'var(--owt-color-border, #C4C4C4)' } })), mode === 'RegistryView' && !isEditMode && !hideEditButton && (jsxRuntimeExports.jsx("div", { className: "flex justify-center items-center", style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsxs("button", { onClick: handleEdit, className: "font-normal inline-flex items-center gap-2 bg-transparent border-0 p-0 cursor-pointer hover:opacity-80", style: {
5628
+ }, children: crViewData.approvedDate }))] })] })] })), mode === 'RegistryView' && !effectiveHideEditButton && (jsxRuntimeExports.jsx("hr", { className: "w-full", style: { height: '1px', marginTop: !isEditMode ? '10px' : 0, marginBottom: '14px', border: 'none', backgroundColor: 'var(--owt-color-border, #C4C4C4)' } })), mode === 'RegistryView' && !isEditMode && !effectiveHideEditButton && (jsxRuntimeExports.jsx("div", { className: "flex justify-center items-center", style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsxs("button", { onClick: handleEdit, className: "font-normal inline-flex items-center gap-2 bg-transparent border-0 p-0 cursor-pointer hover:opacity-80", style: {
5242
5629
  fontFamily: 'Roboto, sans-serif',
5243
5630
  fontSize: '16px',
5244
5631
  color: 'var(--owt-color-text-muted, #727474)',
@@ -6044,7 +6431,7 @@ const JSONEditorPanel = ({ section, onChange, onReset, context = 'section', }) =
6044
6431
  'widget-data-format.dateConstraint': ['any', 'past-only', 'future-only'],
6045
6432
  'widget-data-format.dateTimeConstraint': ['any', 'past-only', 'future-only'],
6046
6433
  // Widget options
6047
- 'widget-data-options.action': ['show', 'hide', 'enable', 'disable'],
6434
+ 'widget-data-options.action': ['show', 'hide', 'enable', 'disable', 'require'],
6048
6435
  'widget-data-options.condition.operator': CONDITION_OPERATORS,
6049
6436
  };
6050
6437
  }, []);
@@ -7429,7 +7816,7 @@ const removeMask = (value, mask) => {
7429
7816
  };
7430
7817
 
7431
7818
  const TextInputWidget = ({ config }) => {
7432
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
7819
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
7433
7820
  const { translate, translateConfig } = useWidgetTranslation();
7434
7821
  // Track raw value separately for masking (to preserve unmasked value internally)
7435
7822
  const formatConfig = widgetConfig['widget-data-format'];
@@ -7566,7 +7953,7 @@ const TextInputWidget = ({ config }) => {
7566
7953
  const label = translateConfig(widgetConfig['widget-label']);
7567
7954
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] TextDisplayWidget 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 }) })] }));
7568
7955
  }
7569
- 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: "flex items-center gap-2 mb-1", children: [jsxRuntimeExports.jsx("input", { type: getInputType(), value: displayValue, onChange: handleChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: placeholder, maxLength: formatConfig?.mask ? undefined : maxLength, inputMode: formatConfig?.currency
7956
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntimeExports.jsx("input", { type: getInputType(), value: displayValue, onChange: handleChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: placeholder, maxLength: formatConfig?.mask ? undefined : maxLength, inputMode: formatConfig?.currency
7570
7957
  ? 'decimal'
7571
7958
  : formatConfig?.characterType === 'numeric' || formatConfig?.characterType === 'numeric-decimal'
7572
7959
  ? 'numeric'
@@ -7589,7 +7976,7 @@ const NumberInputWidget = ({ config }) => {
7589
7976
  }
7590
7977
  return { ...config, 'widget-data-default': normalizedDefault };
7591
7978
  }, [config]);
7592
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
7979
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
7593
7980
  const { translate, translateConfig } = useWidgetTranslation();
7594
7981
  const formatConfig = widgetConfig['widget-data-format'];
7595
7982
  const validationConfig = widgetConfig['widget-data-validation'];
@@ -7720,7 +8107,7 @@ const NumberInputWidget = ({ config }) => {
7720
8107
  const display = numValue !== null ? formatNumber(numValue, formatConfig) : '';
7721
8108
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] NumberDisplayWidget 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 ${textAlignClass}`, title: String(display ?? ''), children: display }) })] }));
7722
8109
  }
7723
- 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: "flex items-center justify-between mb-1", children: [jsxRuntimeExports.jsx("input", { type: "text", inputMode: "decimal", value: displayValue, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: placeholder, maxLength: maxLength, 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 ${textAlignClass} ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (value === null || value === undefined || value === ''))
8110
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1", children: [jsxRuntimeExports.jsx("input", { type: "text", inputMode: "decimal", value: displayValue, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: placeholder, maxLength: maxLength, 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 ${textAlignClass} ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (value === null || value === undefined || value === ''))
7724
8111
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
7725
8112
  : 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }), maxLength && (jsxRuntimeExports.jsxs("span", { className: `text-xs ml-2 flex-shrink-0 ${currentLength > maxLength
7726
8113
  ? 'text-red-500'
@@ -7728,7 +8115,7 @@ const NumberInputWidget = ({ config }) => {
7728
8115
  };
7729
8116
 
7730
8117
  const BooleanWidget = ({ config }) => {
7731
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8118
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
7732
8119
  const { translate, translateConfig } = useWidgetTranslation();
7733
8120
  const formatConfig = widgetConfig['widget-data-format'];
7734
8121
  const representation = formatConfig?.booleanRepresentation || 'true-false';
@@ -7797,7 +8184,7 @@ const BooleanWidget = ({ config }) => {
7797
8184
  }
7798
8185
  // Render based on control type
7799
8186
  if (controlType === 'checkbox') {
7800
- 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] }))] })] }) }));
8187
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { 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", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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] }))] })] }) }));
7801
8188
  }
7802
8189
  if (controlType === 'radio') {
7803
8190
  const containerClass = orientation === 'horizontal'
@@ -7805,10 +8192,10 @@ const BooleanWidget = ({ config }) => {
7805
8192
  : 'flex flex-col items-start gap-2';
7806
8193
  const radioDisabled = !isEnabled || widgetConfig['widget-readonly'];
7807
8194
  const optionDisabledClass = radioDisabled ? 'opacity-50 cursor-not-allowed' : '';
7808
- 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] }))] })] }) }));
8195
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { 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", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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] }))] })] }) }));
7809
8196
  }
7810
8197
  // Toggle/switch control type
7811
- 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
8198
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { 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", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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
7812
8199
  ? 'bg-blue-600 text-white border-blue-600'
7813
8200
  : '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
7814
8201
  ? 'bg-blue-600 text-white border-blue-600'
@@ -7818,7 +8205,7 @@ const BooleanWidget = ({ config }) => {
7818
8205
  };
7819
8206
 
7820
8207
  const DateInputWidget = ({ config }) => {
7821
- const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
8208
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
7822
8209
  const formValues = reactRedux.useSelector((state) => state.widget.values);
7823
8210
  const { translateConfig } = useWidgetTranslation();
7824
8211
  const formatConfig = widgetConfig['widget-data-format'];
@@ -8019,7 +8406,7 @@ const DateInputWidget = ({ config }) => {
8019
8406
  }
8020
8407
  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 }) })] }));
8021
8408
  }
8022
- 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
8409
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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
8023
8410
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8024
8411
  : '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] })] })] }) }));
8025
8412
  };
@@ -8309,7 +8696,7 @@ const validateDateTimeConstraints = (date, minDateTime, maxDateTime, constraint)
8309
8696
  };
8310
8697
 
8311
8698
  const DateTimeInputWidget = ({ config }) => {
8312
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8699
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8313
8700
  const { translate, translateConfig } = useWidgetTranslation();
8314
8701
  const formatConfig = widgetConfig['widget-data-format'];
8315
8702
  const optionsConfig = widgetConfig['widget-data-options'];
@@ -8462,29 +8849,33 @@ const DateTimeInputWidget = ({ config }) => {
8462
8849
  }
8463
8850
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] DateTimeDisplayWidget 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 }) })] }));
8464
8851
  }
8465
- 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' ? effectiveMinDateTime : undefined, max: inputMethod === 'picker' ? effectiveMaxDateTime : 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (!value || value === ''))
8852
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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' ? effectiveMinDateTime : undefined, max: inputMethod === 'picker' ? effectiveMaxDateTime : 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (!value || value === ''))
8466
8853
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8467
8854
  : 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8468
8855
  };
8469
8856
 
8470
8857
  const SelectWidget = ({ config }) => {
8471
- const { value, error, touched, isEnabled, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8858
+ const { value, geoDisplayLabel, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8472
8859
  const { translate, translateConfig } = useWidgetTranslation();
8473
8860
  // For readonly mode, render as display text showing only the selected label
8474
8861
  if (widgetConfig['widget-readonly']) {
8475
8862
  const label = translateConfig(widgetConfig['widget-label']);
8476
8863
  // Find the selected option's label
8477
- const selectedOption = dataSourceOptions.find((option) => option.value === value);
8478
- const displayValue = selectedOption ? selectedOption.label : (value || '-');
8864
+ const selectedOption = dataSourceOptions.find((option) => option.value === value || String(option.value) === String(value));
8865
+ const displayValue = selectedOption
8866
+ ? translateConfig(selectedOption.label)
8867
+ : loading
8868
+ ? (geoDisplayLabel || '-')
8869
+ : (geoDisplayLabel || (value != null && value !== '' ? translateConfig(String(value)) : '-'));
8479
8870
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] SelectDisplayWidget 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 }) })] }));
8480
8871
  }
8481
- 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("select", { value: value || '', onChange: (e) => onChange(e.target.value), onBlur: onBlur, disabled: !isEnabled || loading || widgetConfig['widget-readonly'], 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (!value || value === ''))
8872
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("select", { value: value || '', onChange: (e) => onChange(e.target.value === '' ? undefined : e.target.value), onBlur: onBlur, disabled: !isEnabled || loading || widgetConfig['widget-readonly'], 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (!value || value === ''))
8482
8873
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8483
- : 'border-gray-300'} ${!isEnabled || loading || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']), children: [jsxRuntimeExports.jsx("option", { value: "", children: translate('common.select') }), dataSourceOptions.map((option) => (jsxRuntimeExports.jsx("option", { value: option.value, children: option.label }, option.value)))] }), loading && (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500 mt-1", children: translate('common.loadingOptions') })), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8874
+ : 'border-gray-300'} ${!isEnabled || loading || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']), children: [jsxRuntimeExports.jsx("option", { value: "", children: translate('common.select') }), dataSourceOptions.map((option) => (jsxRuntimeExports.jsx("option", { value: option.value, children: translateConfig(option.label) }, option.value)))] }), loading && (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500 mt-1", children: translate('common.loadingOptions') })), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8484
8875
  };
8485
8876
 
8486
8877
  const RadioWidget = ({ config }) => {
8487
- const { value, error, touched, isEnabled, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8878
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8488
8879
  const { translate, translateConfig } = useWidgetTranslation();
8489
8880
  const formatConfig = widgetConfig['widget-data-format'];
8490
8881
  const layout = formatConfig?.layout || widgetConfig['widget-orientation'] || 'vertical';
@@ -8547,14 +8938,16 @@ const RadioWidget = ({ config }) => {
8547
8938
  if (widgetConfig['widget-readonly']) {
8548
8939
  const label = translateConfig(widgetConfig['widget-label']);
8549
8940
  const selectedOption = processedOptions.find(opt => opt.value === currentValue);
8550
- const displayValue = selectedOption ? selectedOption.label : (allowUnset && currentValue === null ? '-' : '');
8941
+ const displayValue = selectedOption
8942
+ ? translateConfig(selectedOption.label)
8943
+ : (allowUnset && currentValue === null ? '-' : '');
8551
8944
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] RadioDisplayWidget 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 }) })] }));
8552
8945
  }
8553
- 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') })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { 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: handleUnset, 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: "-" })] })), 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: "radio", name: widgetConfig['widget-id'], value: option.value, checked: currentValue === option.value, onChange: (e) => handleChange(option.value), 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: translateConfig(option.label) })] }, option.value)))] })) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8946
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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') })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { 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: handleUnset, 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: "-" })] })), 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: "radio", name: widgetConfig['widget-id'], value: option.value, checked: currentValue === option.value, onChange: (e) => handleChange(option.value), 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: translateConfig(option.label) })] }, option.value)))] })) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8554
8947
  };
8555
8948
 
8556
8949
  const CheckboxWidget = ({ config }) => {
8557
- const { value, error, touched, isEnabled, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8950
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8558
8951
  const { translate, translateConfig } = useWidgetTranslation();
8559
8952
  const hasDataSource = !!widgetConfig['widget-data-source'];
8560
8953
  const formatConfig = widgetConfig['widget-data-format'];
@@ -8569,7 +8962,7 @@ const CheckboxWidget = ({ config }) => {
8569
8962
  const displayValue = isChecked ? 'Yes' : 'No';
8570
8963
  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 }) })] }));
8571
8964
  }
8572
- 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] }))] })] }) }));
8965
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { 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", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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] }))] })] }) }));
8573
8966
  }
8574
8967
  // Multiple checkboxes (with data source) - for array values
8575
8968
  // Process and sort options if needed
@@ -8639,7 +9032,7 @@ const CheckboxWidget = ({ config }) => {
8639
9032
  : '-';
8640
9033
  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 }) })] }));
8641
9034
  }
8642
- 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] }))] })] }) }));
9035
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { 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", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), 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] }))] })] }) }));
8643
9036
  };
8644
9037
 
8645
9038
  const SimpleTableWidget = ({ config }) => {
@@ -8690,7 +9083,7 @@ const SimpleTableWidget = ({ config }) => {
8690
9083
  };
8691
9084
 
8692
9085
  const ArrayWidget = ({ config }) => {
8693
- const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
9086
+ const { value, error, touched, isEnabled, isRequired, onChange, config: widgetConfig, } = useBaseWidget({ config });
8694
9087
  const { translate, translateConfig } = useWidgetTranslation();
8695
9088
  const items = Array.isArray(value) ? value : [];
8696
9089
  const itemConfig = widgetConfig['widget-item'];
@@ -8714,7 +9107,7 @@ const ArrayWidget = ({ config }) => {
8714
9107
  newItems[index] = newValue;
8715
9108
  onChange(newItems);
8716
9109
  };
8717
- return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px]", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start mb-2", 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 flex justify-between items-center", children: [jsxRuntimeExports.jsx("div", { className: "flex-1" }), operations.add && !isReadonly && isEnabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: addItem, className: "px-3 py-1 text-sm bg-blue-500 text-white hover:bg-blue-600", style: { borderRadius: '15px' }, children: addLabel }))] })] }), items.length === 0 ? (jsxRuntimeExports.jsxs("div", { className: "text-gray-500 text-sm py-4 text-center border border-gray-300 rounded", children: [translate('common.noItems'), ". ", operations.add && !isReadonly && translate('common.clickToAdd', { label: addLabel })] })) : (jsxRuntimeExports.jsx("div", { className: "space-y-2", children: items.map((itemValue, index) => {
9110
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px]", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start mb-2", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0 flex justify-between items-center", children: [jsxRuntimeExports.jsx("div", { className: "flex-1" }), operations.add && !isReadonly && isEnabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: addItem, className: "px-3 py-1 text-sm bg-blue-500 text-white hover:bg-blue-600", style: { borderRadius: '15px' }, children: addLabel }))] })] }), items.length === 0 ? (jsxRuntimeExports.jsxs("div", { className: "text-gray-500 text-sm py-4 text-center border border-gray-300 rounded", children: [translate('common.noItems'), ". ", operations.add && !isReadonly && translate('common.clickToAdd', { label: addLabel })] })) : (jsxRuntimeExports.jsx("div", { className: "space-y-2", children: items.map((itemValue, index) => {
8718
9111
  ({
8719
9112
  ...itemConfig,
8720
9113
  'widget-id': `${widgetConfig['widget-id']}-item-${index}`,
@@ -8725,7 +9118,7 @@ const ArrayWidget = ({ config }) => {
8725
9118
  };
8726
9119
 
8727
9120
  const IterableAccordionWidget = ({ config }) => {
8728
- const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
9121
+ const { value, error, touched, isEnabled, isRequired, onChange, config: widgetConfig, } = useBaseWidget({ config });
8729
9122
  const { translate, translateConfig } = useWidgetTranslation();
8730
9123
  const items = Array.isArray(value) ? value : [];
8731
9124
  const itemConfig = widgetConfig['widget-item'];
@@ -8774,7 +9167,7 @@ const IterableAccordionWidget = ({ config }) => {
8774
9167
  newItems[index] = newValue;
8775
9168
  onChange(newItems);
8776
9169
  };
8777
- return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px]", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start mb-2", 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 flex justify-between items-center", children: [jsxRuntimeExports.jsx("div", { className: "flex-1" }), operations.add && !isReadonly && isEnabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: addItem, className: "px-3 py-1 text-sm bg-blue-500 text-white hover:bg-blue-600", style: { borderRadius: '15px' }, children: addLabel }))] })] }), items.length === 0 ? (jsxRuntimeExports.jsxs("div", { className: "text-gray-500 text-sm py-4 text-center border border-gray-300 rounded", children: [translate('common.noItems'), ". ", operations.add && !isReadonly && translate('common.clickToAdd', { label: addLabel })] })) : (jsxRuntimeExports.jsx("div", { className: "space-y-2", children: items.map((itemValue, index) => {
9170
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px]", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start mb-2", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0 flex justify-between items-center", children: [jsxRuntimeExports.jsx("div", { className: "flex-1" }), operations.add && !isReadonly && isEnabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: addItem, className: "px-3 py-1 text-sm bg-blue-500 text-white hover:bg-blue-600", style: { borderRadius: '15px' }, children: addLabel }))] })] }), items.length === 0 ? (jsxRuntimeExports.jsxs("div", { className: "text-gray-500 text-sm py-4 text-center border border-gray-300 rounded", children: [translate('common.noItems'), ". ", operations.add && !isReadonly && translate('common.clickToAdd', { label: addLabel })] })) : (jsxRuntimeExports.jsx("div", { className: "space-y-2", children: items.map((itemValue, index) => {
8778
9171
  const isCollapsed = collapsedItems[index] ?? defaultCollapsed;
8779
9172
  const parentPath = widgetConfig['widget-data-path'];
8780
9173
  const childPath = itemConfig['widget-data-path'];
@@ -8813,7 +9206,7 @@ const IterableAccordionWidget = ({ config }) => {
8813
9206
  };
8814
9207
 
8815
9208
  const PhoneInputWidget = ({ config }) => {
8816
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
9209
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8817
9210
  const { translate, translateConfig } = useWidgetTranslation();
8818
9211
  // Use formatted value if available, otherwise raw value
8819
9212
  const displayValue = formattedValue !== undefined && formattedValue !== value
@@ -8824,13 +9217,13 @@ const PhoneInputWidget = ({ config }) => {
8824
9217
  const label = translateConfig(widgetConfig['widget-label']);
8825
9218
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] PhoneDisplayWidget 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 || '-' }) })] }));
8826
9219
  }
8827
- 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: "tel", value: displayValue, onChange: (e) => onChange(e.target.value), onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: translateConfig(widgetConfig['widget-data-placeholder']), 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (!value || value === ''))
9220
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsx("input", { type: "tel", value: displayValue, onChange: (e) => onChange(e.target.value), onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: translateConfig(widgetConfig['widget-data-placeholder']), 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (!value || value === ''))
8828
9221
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8829
9222
  : 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8830
9223
  };
8831
9224
 
8832
9225
  const CurrencyInputWidget = ({ config }) => {
8833
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
9226
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8834
9227
  const { translate, translateConfig } = useWidgetTranslation();
8835
9228
  // For input, use raw numeric value; formatted value is for display only
8836
9229
  const numericValue = typeof value === 'number' ? value : (value ? parseFloat(String(value)) : '');
@@ -8852,7 +9245,7 @@ const CurrencyInputWidget = ({ config }) => {
8852
9245
  const display = formattedValue || (value !== null && value !== undefined ? String(value) : '-');
8853
9246
  return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] CurrencyDisplayWidget 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(display ?? ''), children: display }) })] }));
8854
9247
  }
8855
- 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: "relative", children: [jsxRuntimeExports.jsx("input", { type: "text", inputMode: "decimal", value: numericValue, onChange: handleChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: translateConfig(widgetConfig['widget-data-placeholder']), 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (value === null || value === undefined || value === ''))
9248
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: translateConfig(widgetConfig['widget-label']), required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { className: "relative", children: [jsxRuntimeExports.jsx("input", { type: "text", inputMode: "decimal", value: numericValue, onChange: handleChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: translateConfig(widgetConfig['widget-data-placeholder']), 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 ${(touched && error.length > 0) || (widgetConfig['widget-required'] && (value === null || value === undefined || value === ''))
8856
9249
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8857
9250
  : 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }), formattedValue && formattedValue !== String(value) && (jsxRuntimeExports.jsx("span", { className: "absolute right-3 top-2 text-gray-500 text-sm", children: formattedValue }))] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
8858
9251
  };
@@ -8958,7 +9351,7 @@ const TableCellSelect = ({ config, value, onValueChange }) => {
8958
9351
  // Use useBaseWidget to get data source options (it handles loading)
8959
9352
  const { dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8960
9353
  const isReadonly = config['widget-readonly'] || false;
8961
- return (jsxRuntimeExports.jsxs("div", { className: "table-cell-field w-full", children: [jsxRuntimeExports.jsxs("select", { value: value || '', onChange: (e) => onValueChange(e.target.value), disabled: isReadonly || loading, className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly || loading ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
9354
+ return (jsxRuntimeExports.jsxs("div", { className: "table-cell-field w-full", children: [jsxRuntimeExports.jsxs("select", { value: value || '', onChange: (e) => onValueChange(e.target.value === '' ? undefined : e.target.value), disabled: isReadonly || loading, className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly || loading ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
8962
9355
  borderRadius: '10px',
8963
9356
  borderColor: 'var(--owt-widget-input-border, #C4C4C4)',
8964
9357
  backgroundColor: isReadonly || loading ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
@@ -8972,7 +9365,7 @@ const SelectDisplayValue$1 = ({ config, value }) => {
8972
9365
  if (value === null || value === undefined || value === '') {
8973
9366
  return jsxRuntimeExports.jsx("span", { children: "-" });
8974
9367
  }
8975
- const selectedOption = dataSourceOptions.find((option) => option.value === value);
9368
+ const selectedOption = dataSourceOptions.find((option) => option.value === value || String(option.value) === String(value));
8976
9369
  return jsxRuntimeExports.jsx("span", { children: selectedOption ? selectedOption.label : String(value) });
8977
9370
  };
8978
9371
  const TableCellText = ({ config, value, onValueChange }) => {
@@ -9695,6 +10088,23 @@ const TableWidget = ({ config }) => {
9695
10088
  }, children: translate('common.cancel') || 'Cancel' })] }) })] }))] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] })] }));
9696
10089
  };
9697
10090
 
10091
+ const isUnsetRowValue = (value) => value === null || value === undefined || value === '';
10092
+ /** Match TableWidget cell styling for add / update / delete rows */
10093
+ const getRowCellStyle = (editAction) => {
10094
+ if (editAction === 'ADD') {
10095
+ return { color: 'var(--owt-color-success, #16A34A)' };
10096
+ }
10097
+ if (editAction === 'DELETE') {
10098
+ return {
10099
+ color: 'var(--owt-color-error, #B91C1C)',
10100
+ textDecoration: 'line-through',
10101
+ };
10102
+ }
10103
+ if (editAction === 'UPDATE') {
10104
+ return { color: 'var(--owt-color-warning, #F59E0B)' };
10105
+ }
10106
+ return {};
10107
+ };
9698
10108
  // Display select value label in view mode
9699
10109
  const SelectDisplayValue = ({ config, value }) => {
9700
10110
  const { dataSourceOptions, loading } = useBaseWidget({ config });
@@ -9702,53 +10112,57 @@ const SelectDisplayValue = ({ config, value }) => {
9702
10112
  return jsxRuntimeExports.jsx("span", { children: "-" });
9703
10113
  if (value === null || value === undefined || value === '')
9704
10114
  return jsxRuntimeExports.jsx("span", { children: "-" });
9705
- const selectedOption = dataSourceOptions.find((option) => option.value === value);
10115
+ const selectedOption = dataSourceOptions.find((option) => option.value === value || String(option.value) === String(value));
9706
10116
  return jsxRuntimeExports.jsx("span", { children: selectedOption ? selectedOption.label : String(value) });
9707
10117
  };
10118
+ /** Isolated dialog field — avoids re-running data-source effects when sibling fields update. */
10119
+ const DialogTableField = React.memo(function DialogTableField({ col, cellWidgetId, dialogRowValues, isReadonly, }) {
10120
+ const widgetType = col.widget || 'text';
10121
+ const fieldConfig = React.useMemo(() => {
10122
+ return {
10123
+ ...col,
10124
+ widget: widgetType,
10125
+ 'widget-type': col['widget-type'] || 'input',
10126
+ 'widget-id': cellWidgetId,
10127
+ 'widget-label': col['widget-label'],
10128
+ 'widget-readonly': isReadonly || col['widget-readonly'] === true,
10129
+ 'widget-data-path': undefined,
10130
+ 'widget-data-default': col['widget-data-default'],
10131
+ 'widget-data-options': undefined,
10132
+ 'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
10133
+ };
10134
+ }, [col, cellWidgetId, dialogRowValues, isReadonly, widgetType]);
10135
+ return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig }) }));
10136
+ });
9708
10137
  /**
9709
10138
  * Dialog table widget:
9710
10139
  * - Table displays a subset of columns (n out of x)
9711
10140
  * - Add/Edit happens in a modal dialog that shows ALL columns as a form
9712
- *
9713
- * Usage in schema:
9714
- * {
9715
- * "widget": "dialog-table",
9716
- * "widget-type": "table",
9717
- * "widget-label": "Household Members",
9718
- * "widget-id": "householdMembers",
9719
- * "widget-data-path": "household.members",
9720
- * "widget-data-columns": [ ...all columns... ],
9721
- * "widget-data-visible-columns": ["firstName", "lastName", "dob"], // optional override; default = by column flag
9722
- * // Per-column control (recommended): set "column-visible-in-table": false to hide it in the table
9723
- * "widget-data-operations": { "add": true, "edit": true, "remove": true }
9724
- * }
9725
10141
  */
9726
10142
  const DialogTableWidget = ({ config }) => {
9727
10143
  const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
9728
10144
  const { translate, translateConfig } = useWidgetTranslation();
9729
10145
  const dispatch = reactRedux.useDispatch();
9730
- const storeValues = reactRedux.useSelector((state) => state.widget?.values ?? {});
9731
10146
  const rows = Array.isArray(value) ? value : [];
9732
10147
  const columns = widgetConfig['widget-data-columns'] || [];
9733
10148
  const operations = widgetConfig['widget-data-operations'] || {};
9734
10149
  const isReadonly = widgetConfig['widget-readonly'] || false;
10150
+ // Soft-delete (keep row, red + strikethrough) whenever remove is allowed — matches TableWidget
10151
+ const shouldSoftDeleteOnRemove = !isReadonly && !!operations.remove;
9735
10152
  const visibleColumnKeys = widgetConfig['widget-data-visible-columns'];
9736
10153
  const visibleColumns = React.useMemo(() => {
9737
- // 1) If explicit list provided, it wins
9738
10154
  if (Array.isArray(visibleColumnKeys) && visibleColumnKeys.length > 0) {
9739
10155
  const keySet = new Set(visibleColumnKeys);
9740
10156
  return columns.filter((c) => keySet.has(c['column-key']));
9741
10157
  }
9742
- // 2) Otherwise decide per column (default = visible)
9743
10158
  return columns.filter((c) => c['column-visible-in-table'] !== false);
9744
10159
  }, [columns, visibleColumnKeys]);
9745
10160
  const [dialogOpen, setDialogOpen] = React.useState(false);
9746
10161
  const [dialogMode, setDialogMode] = React.useState('add');
9747
10162
  const [activeRowIndex, setActiveRowIndex] = React.useState(null);
9748
- const [formData, setFormData] = React.useState({});
9749
- /** Unique per dialog open so Redux widget ids don't reuse stale values across rows/add sessions */
9750
10163
  const dialogSessionRef = React.useRef(0);
9751
10164
  const [dialogSessionId, setDialogSessionId] = React.useState(0);
10165
+ const membersWidgetId = widgetConfig['widget-id'];
9752
10166
  const addDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-add']) ||
9753
10167
  translate('table.addRecordDialog') ||
9754
10168
  'Add record';
@@ -9759,19 +10173,35 @@ const DialogTableWidget = ({ config }) => {
9759
10173
  const emptyRow = {};
9760
10174
  columns.forEach((col) => {
9761
10175
  const key = col['column-key'];
9762
- emptyRow[key] = col['widget-data-default'] ?? '';
10176
+ if (col['widget-data-default'] !== undefined) {
10177
+ emptyRow[key] = col['widget-data-default'];
10178
+ }
10179
+ else if (col.widget === 'checkbox') {
10180
+ emptyRow[key] = false;
10181
+ }
9763
10182
  });
9764
10183
  return emptyRow;
9765
10184
  }, [columns]);
9766
- const dialogFieldWidgetId = React.useCallback((columnKey) => `${widgetConfig['widget-id']}-dlg-${dialogSessionId}-${columnKey}`, [widgetConfig, dialogSessionId]);
10185
+ const dialogFieldWidgetId = React.useCallback((sessionId, columnKey) => `${membersWidgetId}-dlg-${sessionId}-${columnKey}`, [membersWidgetId]);
9767
10186
  const resetDialogWidgets = React.useCallback((sessionId) => {
9768
10187
  if (sessionId <= 0)
9769
10188
  return;
9770
10189
  columns.forEach((col) => {
9771
- const wid = `${widgetConfig['widget-id']}-dlg-${sessionId}-${col['column-key']}`;
9772
- dispatch(resetWidget(wid));
10190
+ dispatch(resetWidget(dialogFieldWidgetId(sessionId, col['column-key'])));
10191
+ });
10192
+ }, [columns, dialogFieldWidgetId, dispatch]);
10193
+ const seedDialogReduxValues = React.useCallback((sessionId, rowData) => {
10194
+ const seeds = {};
10195
+ columns.forEach((col) => {
10196
+ const key = col['column-key'];
10197
+ if (rowData[key] !== undefined) {
10198
+ seeds[dialogFieldWidgetId(sessionId, key)] = rowData[key];
10199
+ }
9773
10200
  });
9774
- }, [columns, widgetConfig, dispatch]);
10201
+ if (Object.keys(seeds).length > 0) {
10202
+ dispatch(setValues(seeds));
10203
+ }
10204
+ }, [columns, dialogFieldWidgetId, dispatch]);
9775
10205
  const beginDialogSession = React.useCallback(() => {
9776
10206
  dialogSessionRef.current += 1;
9777
10207
  const nextSession = dialogSessionRef.current;
@@ -9780,15 +10210,21 @@ const DialogTableWidget = ({ config }) => {
9780
10210
  }, []);
9781
10211
  const openAddDialog = React.useCallback(() => {
9782
10212
  resetDialogWidgets(dialogSessionId);
9783
- beginDialogSession();
10213
+ const sessionId = beginDialogSession();
10214
+ seedDialogReduxValues(sessionId, buildEmptyRow());
9784
10215
  setDialogMode('add');
9785
10216
  setActiveRowIndex(null);
9786
- setFormData(buildEmptyRow());
9787
10217
  setDialogOpen(true);
9788
- }, [buildEmptyRow, beginDialogSession, resetDialogWidgets, dialogSessionId]);
10218
+ }, [
10219
+ buildEmptyRow,
10220
+ beginDialogSession,
10221
+ resetDialogWidgets,
10222
+ dialogSessionId,
10223
+ seedDialogReduxValues,
10224
+ ]);
9789
10225
  const openEditDialog = React.useCallback((rowIndex) => {
9790
10226
  resetDialogWidgets(dialogSessionId);
9791
- beginDialogSession();
10227
+ const sessionId = beginDialogSession();
9792
10228
  const row = rows[rowIndex] || {};
9793
10229
  const nextFormData = buildEmptyRow();
9794
10230
  columns.forEach((col) => {
@@ -9796,44 +10232,71 @@ const DialogTableWidget = ({ config }) => {
9796
10232
  if (row[key] !== undefined)
9797
10233
  nextFormData[key] = row[key];
9798
10234
  });
10235
+ seedDialogReduxValues(sessionId, nextFormData);
9799
10236
  setDialogMode('edit');
9800
10237
  setActiveRowIndex(rowIndex);
9801
- setFormData(nextFormData);
9802
10238
  setDialogOpen(true);
9803
- }, [rows, columns, buildEmptyRow, resetDialogWidgets, dialogSessionId, beginDialogSession]);
10239
+ }, [
10240
+ rows,
10241
+ columns,
10242
+ buildEmptyRow,
10243
+ resetDialogWidgets,
10244
+ dialogSessionId,
10245
+ beginDialogSession,
10246
+ seedDialogReduxValues,
10247
+ ]);
9804
10248
  const closeDialog = React.useCallback(() => {
9805
10249
  const sessionToClear = dialogSessionId;
9806
10250
  setDialogOpen(false);
9807
10251
  setActiveRowIndex(null);
9808
- setFormData({});
9809
10252
  resetDialogWidgets(sessionToClear);
9810
10253
  setDialogSessionId(0);
9811
10254
  }, [dialogSessionId, resetDialogWidgets]);
9812
- const updateField = React.useCallback((columnKey, newValue) => {
9813
- setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
9814
- }, []);
9815
- const collectMergedRowPayload = React.useCallback(() => {
9816
- const merged = { ...formData };
10255
+ const dialogStoreValues = reactRedux.useSelector((state) => {
10256
+ if (dialogSessionId <= 0) {
10257
+ return {};
10258
+ }
10259
+ const values = state.widget?.values ?? {};
10260
+ const row = {};
9817
10261
  columns.forEach((col) => {
9818
10262
  const k = col['column-key'];
9819
- const wid = dialogFieldWidgetId(k);
9820
- const fromStore = storeValues[wid];
9821
- if (fromStore !== undefined)
9822
- merged[k] = fromStore;
10263
+ const wid = dialogFieldWidgetId(dialogSessionId, k);
10264
+ if (values[wid] !== undefined) {
10265
+ row[k] = values[wid];
10266
+ }
10267
+ });
10268
+ return row;
10269
+ });
10270
+ const dialogRowValues = dialogStoreValues;
10271
+ const collectMergedRowPayload = React.useCallback(() => dialogStoreValues, [dialogStoreValues]);
10272
+ const finalizeDialogRowPayload = React.useCallback((raw) => {
10273
+ const result = {};
10274
+ columns.forEach((col) => {
10275
+ const key = col['column-key'];
10276
+ if (!shouldShowWidget(col['widget-data-options'], raw)) {
10277
+ return;
10278
+ }
10279
+ const val = raw[key];
10280
+ if (!isUnsetRowValue(val)) {
10281
+ result[key] = val;
10282
+ }
9823
10283
  });
9824
- return merged;
9825
- }, [formData, columns, storeValues, dialogFieldWidgetId]);
10284
+ return result;
10285
+ }, [columns]);
9826
10286
  const saveDialog = React.useCallback(() => {
9827
10287
  const payload = collectMergedRowPayload();
9828
10288
  let hasErrors = false;
9829
10289
  columns.forEach((col) => {
9830
10290
  const key = col['column-key'];
9831
- const cellWidgetId = dialogFieldWidgetId(key);
10291
+ const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
9832
10292
  const isColReadonly = isReadonly || col['widget-readonly'] === true;
9833
10293
  if (isColReadonly)
9834
10294
  return;
10295
+ if (!shouldShowWidget(col['widget-data-options'], payload))
10296
+ return;
9835
10297
  const cellValue = payload[key];
9836
- const validationErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
10298
+ const isRequired = shouldRequireWidget(col['widget-data-options'], payload, col['widget-required']);
10299
+ const validationErrors = validateWidget(cellValue, col['widget-data-validation'], isRequired);
9837
10300
  if (validationErrors && validationErrors.length > 0) {
9838
10301
  hasErrors = true;
9839
10302
  dispatch(setError({ widgetId: cellWidgetId, errors: validationErrors }));
@@ -9846,8 +10309,9 @@ const DialogTableWidget = ({ config }) => {
9846
10309
  if (hasErrors) {
9847
10310
  return;
9848
10311
  }
10312
+ const cleaned = finalizeDialogRowPayload(payload);
9849
10313
  if (dialogMode === 'add') {
9850
- const savedRow = { ...payload, edit_action: 'ADD' };
10314
+ const savedRow = { ...cleaned, edit_action: 'ADD' };
9851
10315
  onChange([...rows, savedRow]);
9852
10316
  closeDialog();
9853
10317
  return;
@@ -9857,15 +10321,43 @@ const DialogTableWidget = ({ config }) => {
9857
10321
  const currentRow = newRows[activeRowIndex] || {};
9858
10322
  const wasDeleted = currentRow.edit_action === 'DELETE';
9859
10323
  const editAction = wasDeleted ? 'UPDATE' : (currentRow.edit_action ?? 'UPDATE');
9860
- newRows[activeRowIndex] = { ...currentRow, ...payload, edit_action: editAction };
10324
+ const merged = { ...currentRow, ...cleaned, edit_action: editAction };
10325
+ columns.forEach((col) => {
10326
+ const key = col['column-key'];
10327
+ if (!(key in cleaned)) {
10328
+ delete merged[key];
10329
+ }
10330
+ });
10331
+ newRows[activeRowIndex] = merged;
9861
10332
  onChange(newRows);
9862
10333
  closeDialog();
9863
10334
  }
9864
- }, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
10335
+ }, [
10336
+ collectMergedRowPayload,
10337
+ finalizeDialogRowPayload,
10338
+ dialogMode,
10339
+ onChange,
10340
+ rows,
10341
+ closeDialog,
10342
+ activeRowIndex,
10343
+ columns,
10344
+ dialogSessionId,
10345
+ dialogFieldWidgetId,
10346
+ isReadonly,
10347
+ dispatch,
10348
+ ]);
9865
10349
  const deleteRow = React.useCallback((rowIndex) => {
9866
- const newRows = rows.filter((_, i) => i !== rowIndex);
9867
- onChange(newRows);
9868
- }, [rows, onChange]);
10350
+ if (shouldSoftDeleteOnRemove) {
10351
+ const newRows = [...rows];
10352
+ newRows[rowIndex] = {
10353
+ ...newRows[rowIndex],
10354
+ edit_action: 'DELETE',
10355
+ };
10356
+ onChange(newRows);
10357
+ return;
10358
+ }
10359
+ onChange(rows.filter((_, i) => i !== rowIndex));
10360
+ }, [rows, onChange, shouldSoftDeleteOnRemove]);
9869
10361
  const getDisplayValue = React.useCallback((rowIndex, column) => {
9870
10362
  const key = column['column-key'];
9871
10363
  const cellValue = rows[rowIndex]?.[key];
@@ -9873,11 +10365,12 @@ const DialogTableWidget = ({ config }) => {
9873
10365
  if (cellValue === null || cellValue === undefined || cellValue === '')
9874
10366
  return '-';
9875
10367
  if (widgetType === 'select')
9876
- return null; // handled by SelectDisplayValue
10368
+ return null;
9877
10369
  if (column['widget-data-format'])
9878
10370
  return formatValue(cellValue, column['widget-data-format'], column.widget);
9879
10371
  return String(cellValue);
9880
10372
  }, [rows]);
10373
+ const visibleDialogColumns = React.useMemo(() => columns.filter((col) => shouldShowWidget(col['widget-data-options'], dialogRowValues)), [columns, dialogRowValues]);
9881
10374
  const tableWidgetId = `dialog-table-widget-${widgetConfig['widget-id']}`;
9882
10375
  const columnSpan = widgetConfig['widget-column-span'] || 2;
9883
10376
  const minWidth = columnSpan * 200;
@@ -9905,37 +10398,40 @@ const DialogTableWidget = ({ config }) => {
9905
10398
  }, children: translate('table.addRecord') || 'Add New Record' }) })), jsxRuntimeExports.jsx("div", { className: "overflow-x-auto border", style: {
9906
10399
  borderRadius: 'var(--owt-widget-table-border-radius, 15px)',
9907
10400
  borderColor: 'var(--owt-widget-table-border-color, #C4C4C4)',
9908
- }, children: jsxRuntimeExports.jsxs("table", { className: "min-w-full", style: { borderCollapse: 'separate', borderSpacing: 0 }, children: [jsxRuntimeExports.jsx("thead", { style: { backgroundColor: 'var(--owt-widget-table-header-bg, #F6F6F6)' }, children: jsxRuntimeExports.jsxs("tr", { style: { borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)' }, children: [visibleColumns.map((col) => (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translateConfig(col['widget-label']) }, col['column-key']))), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translate('common.actions') || 'Actions' }))] }) }), jsxRuntimeExports.jsxs("tbody", { style: { backgroundColor: 'var(--owt-widget-table-body-bg, #FFFFFF)' }, children: [rows.length === 0 && (jsxRuntimeExports.jsx("tr", { children: jsxRuntimeExports.jsxs("td", { colSpan: visibleColumns.length + (((operations.edit || operations.remove) && !isReadonly) ? 1 : 0), className: "px-4 py-6 text-center text-sm", style: { color: 'var(--owt-widget-table-empty-color, #727474)' }, children: [translate('table.noData') || 'No records available.', operations.add && !isReadonly && ` ${translate('table.clickToAdd') || 'Click "Add New Record" to add one.'}`] }) })), rows.map((row, rowIndex) => (jsxRuntimeExports.jsxs("tr", { style: {
9909
- borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
9910
- backgroundColor: row?.edit_action === 'DELETE'
9911
- ? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
9912
- : undefined,
9913
- }, children: [visibleColumns.map((col) => {
9914
- const key = col['column-key'];
9915
- const widgetType = col.widget || 'text';
9916
- const displayValue = getDisplayValue(rowIndex, col);
9917
- if (widgetType === 'select' && displayValue === null) {
9918
- const displayConfig = {
9919
- ...col,
9920
- 'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
9921
- 'widget-label': '',
9922
- 'widget-readonly': true,
9923
- 'widget-data-path': undefined,
9924
- };
9925
- return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: displayConfig, value: row?.[key] }) }) }, key));
9926
- }
9927
- return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: displayValue }) }, key));
9928
- }), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", style: { minWidth: '120px' }, children: jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [operations.edit && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => openEditDialog(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
9929
- borderRadius: 'var(--owt-btn-border-radius, 10px)',
9930
- color: 'var(--owt-color-primary-dark, #F07B1A)',
9931
- backgroundColor: 'transparent',
9932
- border: 'none',
9933
- }, children: translate('common.edit') || 'Edit' })), operations.remove && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => deleteRow(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
9934
- borderRadius: 'var(--owt-btn-border-radius, 10px)',
9935
- color: 'var(--owt-color-error, #B91C1C)',
9936
- backgroundColor: 'transparent',
9937
- border: 'none',
9938
- }, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex)))] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] }), dialogOpen && (jsxRuntimeExports.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50", style: { backgroundColor: 'rgba(0,0,0,0.5)' }, children: jsxRuntimeExports.jsxs("div", { className: "rounded-lg p-6 w-full mx-4", style: {
10401
+ }, children: jsxRuntimeExports.jsxs("table", { className: "min-w-full", style: { borderCollapse: 'separate', borderSpacing: 0 }, children: [jsxRuntimeExports.jsx("thead", { style: { backgroundColor: 'var(--owt-widget-table-header-bg, #F6F6F6)' }, children: jsxRuntimeExports.jsxs("tr", { style: { borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)' }, children: [visibleColumns.map((col) => (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translateConfig(col['widget-label']) }, col['column-key']))), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translate('common.actions') || 'Actions' }))] }) }), jsxRuntimeExports.jsxs("tbody", { style: { backgroundColor: 'var(--owt-widget-table-body-bg, #FFFFFF)' }, children: [rows.length === 0 && (jsxRuntimeExports.jsx("tr", { children: jsxRuntimeExports.jsxs("td", { colSpan: visibleColumns.length + (((operations.edit || operations.remove) && !isReadonly) ? 1 : 0), className: "px-4 py-6 text-center text-sm", style: { color: 'var(--owt-widget-table-empty-color, #727474)' }, children: [translate('table.noData') || 'No records available.', operations.add && !isReadonly && ` ${translate('table.clickToAdd') || 'Click "Add New Record" to add one.'}`] }) })), rows.map((row, rowIndex) => {
10402
+ const cellStyle = getRowCellStyle(row?.edit_action);
10403
+ return (jsxRuntimeExports.jsxs("tr", { style: {
10404
+ borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
10405
+ backgroundColor: row?.edit_action === 'DELETE'
10406
+ ? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
10407
+ : undefined,
10408
+ }, children: [visibleColumns.map((col) => {
10409
+ const key = col['column-key'];
10410
+ const widgetType = col.widget || 'text';
10411
+ const displayValue = getDisplayValue(rowIndex, col);
10412
+ if (widgetType === 'select' && displayValue === null) {
10413
+ const displayConfig = {
10414
+ ...col,
10415
+ 'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
10416
+ 'widget-label': '',
10417
+ 'widget-readonly': true,
10418
+ 'widget-data-path': undefined,
10419
+ };
10420
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: displayConfig, value: row?.[key] }) }) }, key));
10421
+ }
10422
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: displayValue }) }, key));
10423
+ }), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", style: { minWidth: '120px' }, children: jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [operations.edit && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => openEditDialog(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
10424
+ borderRadius: 'var(--owt-btn-border-radius, 10px)',
10425
+ color: 'var(--owt-color-primary-dark, #F07B1A)',
10426
+ backgroundColor: 'transparent',
10427
+ border: 'none',
10428
+ }, children: translate('common.edit') || 'Edit' })), operations.remove && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => deleteRow(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
10429
+ borderRadius: 'var(--owt-btn-border-radius, 10px)',
10430
+ color: 'var(--owt-color-error, #B91C1C)',
10431
+ backgroundColor: 'transparent',
10432
+ border: 'none',
10433
+ }, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex));
10434
+ })] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] }), dialogOpen && (jsxRuntimeExports.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50", style: { backgroundColor: 'rgba(0,0,0,0.5)' }, children: jsxRuntimeExports.jsxs("div", { className: "rounded-lg p-6 w-full mx-4", style: {
9939
10435
  maxWidth: '900px',
9940
10436
  backgroundColor: 'var(--owt-color-bg, #FFFFFF)',
9941
10437
  borderRadius: 'var(--owt-widget-card-border-radius, 20px)',
@@ -9946,22 +10442,10 @@ const DialogTableWidget = ({ config }) => {
9946
10442
  cursor: 'pointer',
9947
10443
  fontSize: '20px',
9948
10444
  lineHeight: 1,
9949
- }, "aria-label": "Close", children: "\u00D7" })] }), jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", style: { maxHeight: '70vh', overflow: 'auto' }, children: columns.map((col) => {
10445
+ }, "aria-label": "Close", children: "\u00D7" })] }), jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", style: { maxHeight: '70vh', overflow: 'auto' }, children: visibleDialogColumns.map((col) => {
9950
10446
  const key = col['column-key'];
9951
- const widgetType = col.widget || 'text';
9952
- const cellWidgetId = dialogFieldWidgetId(key);
9953
- const initialValue = formData[key] ?? col['widget-data-default'] ?? '';
9954
- const fieldConfig = {
9955
- ...col,
9956
- widget: widgetType,
9957
- 'widget-type': col['widget-type'] || 'input',
9958
- 'widget-id': cellWidgetId,
9959
- 'widget-label': col['widget-label'],
9960
- 'widget-readonly': isReadonly || col['widget-readonly'] === true,
9961
- 'widget-data-path': undefined,
9962
- 'widget-data-default': initialValue,
9963
- };
9964
- return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig, schemaData: { [cellWidgetId]: initialValue }, onValueChange: (_widgetId, newValue) => updateField(key, newValue) }) }, `${dialogSessionId}-${key}`));
10447
+ const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
10448
+ return (jsxRuntimeExports.jsx(DialogTableField, { col: col, cellWidgetId: cellWidgetId, dialogRowValues: dialogRowValues, isReadonly: isReadonly }, `${dialogSessionId}-${key}`));
9965
10449
  }) }, `dialog-fields-${dialogSessionId}`), jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3 mt-6", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: closeDialog, className: "px-4 py-2 text-sm font-medium", style: {
9966
10450
  borderRadius: 'var(--owt-btn-border-radius, 10px)',
9967
10451
  border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',
@@ -10151,13 +10635,13 @@ const ProfileWidget = ({ config }) => {
10151
10635
  if (placeholder) {
10152
10636
  placeholder.style.display = 'flex';
10153
10637
  }
10154
- } })) : null, jsxRuntimeExports.jsx("div", { className: "profile-avatar-placeholder", style: { display: imageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) })] }), jsxRuntimeExports.jsxs("div", { className: "profile-info", children: [displayName && (jsxRuntimeExports.jsx("div", { className: "profile-name", children: displayName })), idValue && (jsxRuntimeExports.jsxs("div", { className: "profile-id", children: [showIdLabel && (jsxRuntimeExports.jsx("span", { className: "profile-id-label", children: "ID :" })), jsxRuntimeExports.jsx("span", { className: "profile-id-value", children: idValue })] }))] })] })] }));
10638
+ } })) : null, jsxRuntimeExports.jsx("div", { className: "profile-avatar-placeholder", style: { display: imageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$h, alt: "Profile Placeholder" }) })] }), jsxRuntimeExports.jsxs("div", { className: "profile-info", children: [displayName && (jsxRuntimeExports.jsx("div", { className: "profile-name", children: displayName })), idValue && (jsxRuntimeExports.jsxs("div", { className: "profile-id", children: [showIdLabel && (jsxRuntimeExports.jsx("span", { className: "profile-id-label", children: "ID :" })), jsxRuntimeExports.jsx("span", { className: "profile-id-value", children: idValue })] }))] })] })] }));
10155
10639
  };
10156
10640
 
10157
10641
  const TextAreaWidget = ({ config }) => {
10158
10642
  // Check readonly early from original config
10159
10643
  const isReadonly = config['widget-readonly'] || false;
10160
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
10644
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
10161
10645
  const { translate, translateConfig } = useWidgetTranslation();
10162
10646
  const formatConfig = widgetConfig['widget-data-format'] || {};
10163
10647
  const validationConfig = widgetConfig['widget-data-validation'] || {};
@@ -10205,7 +10689,6 @@ const TextAreaWidget = ({ config }) => {
10205
10689
  ? translateConfig(widgetConfig['widget-label'])
10206
10690
  : '';
10207
10691
  // Check if required
10208
- const isRequired = widgetConfig['widget-required'] || false;
10209
10692
  // Error display
10210
10693
  const hasError = touched && error && error.length > 0;
10211
10694
  const errorMessage = hasError ? error[0] : '';
@@ -10223,7 +10706,7 @@ const TextAreaWidget = ({ config }) => {
10223
10706
  border: 'none',
10224
10707
  }, children: displayValue }) })] }));
10225
10708
  }
10226
- 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: [label, isRequired && (jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { style: { position: 'relative' }, children: [jsxRuntimeExports.jsx("textarea", { id: widgetConfig['widget-id'], rows: rows, value: getStringValue(), onChange: handleChange, onBlur: onBlur, disabled: !isEnabled, placeholder: placeholder, className: `w-full px-3 py-2 border shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${hasError
10709
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: label, required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { style: { position: 'relative' }, children: [jsxRuntimeExports.jsx("textarea", { id: widgetConfig['widget-id'], rows: rows, value: getStringValue(), onChange: handleChange, onBlur: onBlur, disabled: !isEnabled, placeholder: placeholder, className: `w-full px-3 py-2 border shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${hasError
10227
10710
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
10228
10711
  : 'border-gray-300'} ${!isEnabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: {
10229
10712
  borderRadius: '10px',
@@ -10369,17 +10852,16 @@ const HeaderSectionWidget = ({ config }) => {
10369
10852
  result = searchIn(schemaData);
10370
10853
  return result;
10371
10854
  }, [paths, values, schemaData]);
10372
- const imageVal = findValue('image');
10373
10855
  const imageUrlVal = findValue('imageUrl');
10374
10856
  const [previewUrl, setPreviewUrl] = React.useState(null);
10375
10857
  React.useEffect(() => {
10376
- if (imageVal instanceof File) {
10377
- const url = URL.createObjectURL(imageVal);
10858
+ if (imageUrlVal instanceof File) {
10859
+ const url = URL.createObjectURL(imageUrlVal);
10378
10860
  setPreviewUrl(url);
10379
10861
  return () => URL.revokeObjectURL(url);
10380
10862
  }
10381
10863
  setPreviewUrl(null);
10382
- }, [imageVal]);
10864
+ }, [imageUrlVal]);
10383
10865
  const displayImageUrl = previewUrl || (typeof imageUrlVal === 'string' && imageUrlVal ? imageUrlVal : null);
10384
10866
  const displayName = findValue('name') || '';
10385
10867
  const functionalId = findValue('functionalId') || '';
@@ -10498,14 +10980,16 @@ const HeaderSectionWidget = ({ config }) => {
10498
10980
  const fileInputRef = React.useRef(null);
10499
10981
  const handleImageUpload = React.useCallback((e) => {
10500
10982
  const file = e.target.files?.[0];
10501
- if (!file)
10983
+ if (!file || !paths.imageUrl)
10502
10984
  return;
10503
- updateFieldValue('image', file);
10985
+ dispatch(setValues(setValueByPath({ ...values }, paths.imageUrl, file)));
10504
10986
  e.target.value = '';
10505
- }, [updateFieldValue]);
10987
+ }, [paths.imageUrl, values, dispatch]);
10506
10988
  const handleImageDelete = React.useCallback(() => {
10507
- updateFieldValue('image', '');
10508
- }, [updateFieldValue]);
10989
+ if (!paths.imageUrl)
10990
+ return;
10991
+ dispatch(setValues(setValueByPath({ ...values }, paths.imageUrl, null)));
10992
+ }, [paths.imageUrl, values, dispatch]);
10509
10993
  // ── Scoped class for CSS isolation ────────────────────────────
10510
10994
  const cls = `header-section-widget-${widgetConfig['widget-id']}`;
10511
10995
  // ── RENDER ────────────────────────────────────────────────────
@@ -10814,7 +11298,7 @@ const HeaderSectionWidget = ({ config }) => {
10814
11298
  .parentElement?.querySelector('.hdr-avatar-placeholder');
10815
11299
  if (placeholder)
10816
11300
  placeholder.style.display = 'flex';
10817
- } })) : 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: () => {
11301
+ } })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: displayImageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$h, 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: () => {
10818
11302
  if (isReasonMissing)
10819
11303
  setShowReasonRequired(true);
10820
11304
  }, onChange: (e) => {
@@ -11559,6 +12043,621 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
11559
12043
  }, children: "Close" })] }), jsxRuntimeExports.jsx("iframe", { className: "overlay-iframe", src: overlayUrl, title: "Authentication" })] }) })) : null, jsxRuntimeExports.jsx("div", { className: "auth-content", children: jsxRuntimeExports.jsxs("div", { className: "auth-grid", children: [jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Foundational ID:" }), jsxRuntimeExports.jsx("div", { className: "auth-value auth-value--foundational", children: displayText(foundationalId) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Last authenticated on:" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: tryFormatDateTime(lastAuthenticatedOn) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Expiry date:" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: tryFormatDate(expiryDate) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Last authentication status:" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: jsxRuntimeExports.jsxs("div", { className: "auth-status", "aria-label": `Authentication status: ${statusLabel}`, children: [jsxRuntimeExports.jsx("span", { className: "auth-dot" }), jsxRuntimeExports.jsx("span", { children: statusLabel })] }) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Authentication token (PSUT):" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: jsxRuntimeExports.jsx("div", { className: "auth-token", children: psut ? String(psut) : '-' }) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell auth-cell--action", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", "aria-hidden": true }), jsxRuntimeExports.jsxs("div", { className: "auth-value", children: [jsxRuntimeExports.jsx("button", { type: "button", className: "auth-button", onClick: onAuthenticate, disabled: buttonDisabled, children: buttonBusy ? 'Loading…' : 'Authenticate' }), authError ? (jsxRuntimeExports.jsx("div", { className: "auth-error", style: { marginTop: 8 }, children: authError })) : null] })] })] }) })] })] }));
11560
12044
  };
11561
12045
 
12046
+ /**
12047
+ * Register lookup widget — searchable popup to select a record from any register.
12048
+ * Reads ID from widget-data-path, finds matching register row by internal_record_id, shows display fields.
12049
+ *
12050
+ * Example (individual → household link):
12051
+ *
12052
+ * {
12053
+ * "widget": "register-lookup",
12054
+ * "widget-id": "link_internal_record_id",
12055
+ * "widget-type": "input",
12056
+ * "widget-label": "Household",
12057
+ * "widget-required": true,
12058
+ * "widget-data-path": "<section_register_ids>.link_internal_record_id",
12059
+ * "widget-data-source": {
12060
+ * "type": "api",
12061
+ * "method": "POST",
12062
+ * "params": {
12063
+ * "register_id": "<target_register_id>"
12064
+ * },
12065
+ * "service": "register",
12066
+ * "endpoint": "records"
12067
+ * },
12068
+ * "widget-lookup-config": {
12069
+ * "page_size": 10,
12070
+ * "action_label": "Click to Search Household",
12071
+ * "search_placeholder": "Search by name or ID...",
12072
+ * "select_record_label": "Select Household"
12073
+ * }
12074
+ * }
12075
+ */
12076
+ const normalizeDisplayFields = (row) => {
12077
+ if (!Array.isArray(row.display_fields))
12078
+ return [];
12079
+ return [...row.display_fields]
12080
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
12081
+ .map((f) => ({
12082
+ label: String(f.field_name ?? ''),
12083
+ value: f.value !== null && f.value !== undefined ? String(f.value) : '-',
12084
+ }));
12085
+ };
12086
+ const parsePagination = (pagination, rowCount, size, fallbackPage = 1) => {
12087
+ const totalItems = typeof pagination.number_of_items === 'number' ? pagination.number_of_items : rowCount;
12088
+ const totalPages = typeof pagination.number_of_pages === 'number'
12089
+ ? Math.max(1, pagination.number_of_pages)
12090
+ : totalItems > 0
12091
+ ? Math.max(1, Math.ceil(totalItems / size))
12092
+ : 1;
12093
+ return { totalItems, totalPages, currentPage: pagination.current_page ?? fallbackPage };
12094
+ };
12095
+ const RecordDisplayPanel = ({ row, widgetIdPrefix, className = '', }) => {
12096
+ const { translateConfig } = useWidgetTranslation();
12097
+ const columnFields = normalizeDisplayFields(row).filter((f) => f.label !== 'record_name' && f.label !== 'functional_record_id' && f.label !== 'internal_record_id');
12098
+ const fieldSlot = (widgetId, label, value) => (jsxRuntimeExports.jsx("div", { className: "min-w-0 overflow-hidden", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: {
12099
+ widget: 'display',
12100
+ 'widget-type': 'input',
12101
+ 'widget-id': widgetId,
12102
+ 'widget-label': label,
12103
+ 'widget-readonly': true,
12104
+ 'widget-data-default': value,
12105
+ }, schemaData: { [widgetId]: value } }) }, widgetId));
12106
+ const optionalSlot = (field, slot) => field
12107
+ ? fieldSlot(`${widgetIdPrefix}-${field.label}`, translateConfig(field.label), field.value)
12108
+ : jsxRuntimeExports.jsx("div", { className: "mb-[10px] invisible text-base", children: "\u00A0" }, slot);
12109
+ const column = (showDivider, isFirst, children) => (jsxRuntimeExports.jsxs("div", { className: "relative min-w-0 overflow-hidden", style: { paddingRight: showDivider ? '40px' : undefined, paddingLeft: isFirst ? undefined : '40px' }, children: [children, showDivider && (jsxRuntimeExports.jsx("div", { className: "absolute right-0 top-0 bottom-[5px] w-px", style: { backgroundColor: 'var(--owt-panel-divider-color, #C4C4C4)' } }))] }));
12110
+ return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { children: `
12111
+ .register-lookup-record-panel .DisplayFieldWidget,
12112
+ .register-lookup-record-panel .widget-container {
12113
+ min-width: 0 !important;
12114
+ overflow: hidden !important;
12115
+ }
12116
+ .register-lookup-record-panel .DisplayFieldWidget > .flex-1 {
12117
+ min-width: 0 !important;
12118
+ overflow: hidden !important;
12119
+ }
12120
+ .register-lookup-record-panel .DisplayFieldWidget > .text-base.text-gray-600 {
12121
+ width: 50% !important;
12122
+ min-width: 50% !important;
12123
+ max-width: 50% !important;
12124
+ flex-shrink: 0 !important;
12125
+ overflow: hidden !important;
12126
+ text-overflow: ellipsis !important;
12127
+ white-space: nowrap !important;
12128
+ }
12129
+ .register-lookup-record-panel .DisplayFieldWidget > .flex-1 > .text-gray-900 {
12130
+ overflow: hidden;
12131
+ text-overflow: ellipsis;
12132
+ white-space: nowrap;
12133
+ }
12134
+ ` }), jsxRuntimeExports.jsxs("div", { className: `register-lookup-record-panel grid w-full min-w-0 ${className}`, style: { gridTemplateColumns: 'repeat(3, minmax(200px, 1fr))' }, children: [column(true, true, (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [fieldSlot(`${widgetIdPrefix}-record_name`, translateConfig('record_name'), row.record_name == null || row.record_name === '' ? '-' : String(row.record_name)), fieldSlot(`${widgetIdPrefix}-functional_record_id`, translateConfig('functional_record_id'), row.functional_record_id == null || row.functional_record_id === '' ? '-' : String(row.functional_record_id))] }))), column(true, false, [0, 1, 2].map((i) => optionalSlot(columnFields[i], `mid-${i}`))), column(false, false, [0, 1, 2].map((i) => optionalSlot(columnFields[i + 3], `right-${i}`)))] })] }));
12135
+ };
12136
+ const PaginationFooter = ({ currentPage, totalPages, totalCount, pageSize, onPageChange, onPrev, onNext, translate, embedded, }) => {
12137
+ const [pageInput, setPageInput] = React.useState(String(currentPage));
12138
+ React.useEffect(() => {
12139
+ setPageInput(String(currentPage));
12140
+ }, [currentPage]);
12141
+ const pageStart = totalCount === 0 ? 0 : (currentPage - 1) * pageSize + 1;
12142
+ const pageEnd = totalCount === 0 ? 0 : Math.min(currentPage * pageSize, totalCount);
12143
+ const commitPage = () => {
12144
+ const parsed = parseInt(pageInput, 10);
12145
+ if (!Number.isFinite(parsed)) {
12146
+ setPageInput(String(currentPage));
12147
+ return;
12148
+ }
12149
+ const page = Math.min(Math.max(1, parsed), totalPages);
12150
+ setPageInput(String(page));
12151
+ if (page !== currentPage)
12152
+ onPageChange(page);
12153
+ };
12154
+ return (jsxRuntimeExports.jsxs("div", { className: embedded
12155
+ ? 'flex flex-wrap items-center gap-3 flex-1 min-w-0'
12156
+ : 'flex flex-wrap items-center justify-between gap-3 px-5 py-3 flex-shrink-0 border-t border-gray-200', children: [jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-600", children: [totalCount === 1
12157
+ ? translate('common.record', { count: totalCount, defaultValue: `${totalCount} record` })
12158
+ : translate('common.records', { count: totalCount, defaultValue: `${totalCount} records` }), totalCount > 0 && ` · ${pageStart}-${pageEnd}`] }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: onPrev, disabled: currentPage <= 1, className: "px-3 h-8 text-sm font-medium rounded-[10px] bg-gray-100 text-gray-700 disabled:opacity-40 disabled:cursor-not-allowed", children: translate('common.previous', { defaultValue: 'Prev' }) }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-sm text-gray-600", children: [jsxRuntimeExports.jsx("span", { children: translate('common.page', { defaultValue: 'Page' }) }), jsxRuntimeExports.jsx("input", { type: "text", inputMode: "numeric", value: pageInput, onChange: (e) => setPageInput(e.target.value.replace(/\D/g, '')), onKeyDown: (e) => {
12159
+ if (e.key === 'Enter') {
12160
+ e.preventDefault();
12161
+ commitPage();
12162
+ }
12163
+ }, onBlur: commitPage, className: "w-10 h-8 text-center text-sm text-gray-900 outline-none rounded-[10px] border border-gray-300 bg-white", "aria-label": translate('common.pageNumber', { defaultValue: 'Page number' }) }), jsxRuntimeExports.jsx("span", { children: translate('common.ofPages', { total: totalPages, defaultValue: `of ${totalPages}` }) })] }), jsxRuntimeExports.jsx("button", { type: "button", onClick: onNext, disabled: currentPage >= totalPages, className: "px-3 h-8 text-sm font-medium rounded-[10px] bg-gray-100 text-gray-700 disabled:opacity-40 disabled:cursor-not-allowed", children: translate('common.next', { defaultValue: 'Next' }) })] })] }));
12164
+ };
12165
+ const ResultsTable = ({ rows, selectedRowKey, onRowClick, onRowDoubleClick, }) => {
12166
+ const { translateConfig } = useWidgetTranslation();
12167
+ const columns = rows.length === 0
12168
+ ? []
12169
+ : [
12170
+ { key: 'record_name', header: 'record_name' },
12171
+ ...normalizeDisplayFields(rows[0]).map((f) => ({ key: f.label, header: f.label })),
12172
+ ];
12173
+ return (jsxRuntimeExports.jsx("div", { className: "overflow-auto h-full", children: jsxRuntimeExports.jsxs("table", { className: "w-full text-sm border-collapse", children: [jsxRuntimeExports.jsx("thead", { className: "sticky top-0 z-[1] bg-gray-50", children: jsxRuntimeExports.jsx("tr", { children: columns.map((col) => (jsxRuntimeExports.jsx("th", { className: "text-left px-4 py-2 text-sm font-medium text-gray-600 whitespace-nowrap border-b border-gray-200 bg-gray-50", children: translateConfig(col.header) }, col.key))) }) }), jsxRuntimeExports.jsx("tbody", { children: rows.map((row, idx) => {
12174
+ const tableRowKey = row.internal_record_id ?? idx;
12175
+ const isSelected = selectedRowKey != null && tableRowKey === selectedRowKey;
12176
+ return (jsxRuntimeExports.jsx("tr", { onClick: () => onRowClick(row), onDoubleClick: () => onRowDoubleClick?.(row), className: `cursor-pointer border-b border-gray-100 transition-colors ${isSelected ? 'bg-blue-100' : 'hover:bg-blue-50'}`, children: columns.map((col) => {
12177
+ const cellValue = col.key === 'record_name'
12178
+ ? row.record_name != null
12179
+ ? String(row.record_name)
12180
+ : '-'
12181
+ : normalizeDisplayFields(row).find((f) => f.label === col.key)?.value ?? '-';
12182
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-2 text-sm text-gray-900 whitespace-nowrap", children: cellValue }, col.key));
12183
+ }) }, tableRowKey));
12184
+ }) })] }) }));
12185
+ };
12186
+ const RegisterLookupWidget = ({ config }) => {
12187
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
12188
+ const { translate, translateConfig } = useWidgetTranslation();
12189
+ const { dataSourceRequestHandler } = useWidgetContext();
12190
+ const dataSource = widgetConfig['widget-data-source'];
12191
+ const lookupConfig = widgetConfig['widget-lookup-config'];
12192
+ const pageSize = lookupConfig?.page_size ?? 10;
12193
+ const widgetIdPrefix = `${widgetConfig['widget-id'] || 'register-lookup'}-record`;
12194
+ const [isOpen, setIsOpen] = React.useState(false);
12195
+ const [searchText, setSearchText] = React.useState('');
12196
+ const [searchResults, setSearchResults] = React.useState([]);
12197
+ const [currentPage, setCurrentPage] = React.useState(1);
12198
+ const [totalPages, setTotalPages] = React.useState(1);
12199
+ const [totalCount, setTotalCount] = React.useState(null);
12200
+ const [pendingRow, setPendingRow] = React.useState(null);
12201
+ const [appliedRecord, setAppliedRecord] = React.useState(null);
12202
+ const [isHydrating, setIsHydrating] = React.useState(false);
12203
+ const [modalPos, setModalPos] = React.useState({ x: 80, y: 80 });
12204
+ const [modalSize, setModalSize] = React.useState({ w: 860, h: 520 });
12205
+ const isDragging = React.useRef(false);
12206
+ const dragOrigin = React.useRef({ mouseX: 0, mouseY: 0, posX: 0, posY: 0 });
12207
+ const searchInputRef = React.useRef(null);
12208
+ const hydratedValueRef = React.useRef(null);
12209
+ const fetchRecords = React.useCallback(async (text, page, size) => {
12210
+ if (!dataSource?.service || !dataSource?.endpoint || !dataSourceRequestHandler) {
12211
+ return { rows: [], pagination: {} };
12212
+ }
12213
+ const result = await dataSourceRequestHandler(dataSource.service, dataSource.endpoint, dataSource.method, {
12214
+ ...(dataSource.params || {}),
12215
+ search_text: text,
12216
+ current_page: page,
12217
+ page_size: size,
12218
+ }, { headers: dataSource.headers });
12219
+ return {
12220
+ rows: (result?.records ?? []),
12221
+ pagination: (result?.pagination ?? {}),
12222
+ };
12223
+ }, [dataSource, dataSourceRequestHandler]);
12224
+ const findRecordByValue = React.useCallback(async (recordValue) => {
12225
+ const target = String(recordValue).trim();
12226
+ if (!target)
12227
+ return null;
12228
+ const hydratePageSize = lookupConfig?.hydrate_page_size ?? 50;
12229
+ let page = 1;
12230
+ let totalPages = 1;
12231
+ while (page <= totalPages) {
12232
+ const { rows, pagination } = await fetchRecords('', page, hydratePageSize);
12233
+ const match = rows.find((row) => String(row.internal_record_id ?? '').trim() === target);
12234
+ if (match)
12235
+ return match;
12236
+ totalPages = parsePagination(pagination, rows.length, hydratePageSize).totalPages;
12237
+ if (page >= totalPages)
12238
+ break;
12239
+ page += 1;
12240
+ }
12241
+ return null;
12242
+ }, [fetchRecords, lookupConfig?.hydrate_page_size]);
12243
+ const runSearch = React.useCallback(async (text, page = 1) => {
12244
+ try {
12245
+ const { rows, pagination } = await fetchRecords(text, page, pageSize);
12246
+ const parsed = parsePagination(pagination, rows.length, pageSize, page);
12247
+ setSearchResults(rows);
12248
+ setTotalCount(parsed.totalItems);
12249
+ setTotalPages(parsed.totalPages);
12250
+ setCurrentPage(parsed.currentPage);
12251
+ }
12252
+ catch {
12253
+ setSearchResults([]);
12254
+ setTotalCount(null);
12255
+ setTotalPages(1);
12256
+ setCurrentPage(1);
12257
+ }
12258
+ }, [fetchRecords, pageSize]);
12259
+ React.useEffect(() => {
12260
+ const onMove = (e) => {
12261
+ if (!isDragging.current)
12262
+ return;
12263
+ setModalPos({
12264
+ x: dragOrigin.current.posX + (e.clientX - dragOrigin.current.mouseX),
12265
+ y: dragOrigin.current.posY + (e.clientY - dragOrigin.current.mouseY),
12266
+ });
12267
+ };
12268
+ const onUp = () => { isDragging.current = false; };
12269
+ document.addEventListener('mousemove', onMove);
12270
+ document.addEventListener('mouseup', onUp);
12271
+ return () => {
12272
+ document.removeEventListener('mousemove', onMove);
12273
+ document.removeEventListener('mouseup', onUp);
12274
+ };
12275
+ }, []);
12276
+ const hasValue = value !== null && value !== undefined && value !== '';
12277
+ const applySelection = (row) => {
12278
+ hydratedValueRef.current = row.internal_record_id;
12279
+ onChange(row.internal_record_id);
12280
+ setAppliedRecord(row);
12281
+ setIsOpen(false);
12282
+ };
12283
+ const openLookup = () => {
12284
+ const w = Math.min(Math.round(window.innerWidth * 0.82), 940);
12285
+ const h = Math.min(Math.round(window.innerHeight * 0.72), 560);
12286
+ setModalPos({ x: Math.round((window.innerWidth - w) / 2), y: Math.round((window.innerHeight - h) / 2) });
12287
+ setModalSize({ w, h });
12288
+ setIsOpen(true);
12289
+ setSearchText('');
12290
+ setSearchResults([]);
12291
+ setTotalCount(null);
12292
+ setCurrentPage(1);
12293
+ setTotalPages(1);
12294
+ setPendingRow(appliedRecord);
12295
+ setTimeout(() => searchInputRef.current?.focus(), 50);
12296
+ runSearch('', 1);
12297
+ };
12298
+ React.useEffect(() => {
12299
+ if (!hasValue) {
12300
+ hydratedValueRef.current = null;
12301
+ setAppliedRecord(null);
12302
+ setIsHydrating(false);
12303
+ return;
12304
+ }
12305
+ if (!dataSource?.service || !dataSource?.endpoint || !dataSourceRequestHandler)
12306
+ return;
12307
+ if (hydratedValueRef.current === value)
12308
+ return;
12309
+ let cancelled = false;
12310
+ setIsHydrating(true);
12311
+ setAppliedRecord(null);
12312
+ (async () => {
12313
+ try {
12314
+ const match = await findRecordByValue(value);
12315
+ if (cancelled)
12316
+ return;
12317
+ hydratedValueRef.current = value;
12318
+ setAppliedRecord(match);
12319
+ }
12320
+ catch {
12321
+ if (!cancelled) {
12322
+ hydratedValueRef.current = value;
12323
+ setAppliedRecord(null);
12324
+ }
12325
+ }
12326
+ finally {
12327
+ if (!cancelled)
12328
+ setIsHydrating(false);
12329
+ }
12330
+ })();
12331
+ return () => {
12332
+ cancelled = true;
12333
+ setIsHydrating(false);
12334
+ };
12335
+ }, [hasValue, value, dataSource, dataSourceRequestHandler, findRecordByValue]);
12336
+ const isReadonly = !!widgetConfig['widget-readonly'];
12337
+ const label = translateConfig(widgetConfig['widget-label']);
12338
+ const hasError = (touched && error.length > 0) ||
12339
+ (widgetConfig['widget-required'] && !hasValue);
12340
+ const actionLabel = translateConfig(String(lookupConfig?.action_label ?? `Select ${label}`));
12341
+ const searchPlaceholder = translateConfig(String(lookupConfig?.search_placeholder ?? 'Search...'));
12342
+ const selectRecordLabel = translateConfig(String(lookupConfig?.select_record_label ?? `Select ${label}`));
12343
+ const hydratedPanel = isHydrating ? (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500", children: translate('common.loading', { defaultValue: 'Loading...' }) })) : appliedRecord ? (jsxRuntimeExports.jsx(RecordDisplayPanel, { row: appliedRecord, widgetIdPrefix: `${widgetIdPrefix}-${isReadonly ? 'readonly' : 'applied'}` })) : null;
12344
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] w-full", children: [hasValue ? (jsxRuntimeExports.jsxs("div", { className: "w-full", children: [hydratedPanel, !isReadonly && isEnabled && (jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mt-2", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: openLookup, className: "text-sm underline p-0 border-0 bg-transparent cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1 rounded", style: { color: 'var(--owt-color-info, #2563eb)' }, children: translate('common.change', { defaultValue: 'Change' }) }), jsxRuntimeExports.jsx("button", { type: "button", onClick: (e) => {
12345
+ e.stopPropagation();
12346
+ hydratedValueRef.current = null;
12347
+ onChange(null);
12348
+ setAppliedRecord(null);
12349
+ setPendingRow(null);
12350
+ }, className: "text-sm underline text-red-500 p-0 border-0 bg-transparent cursor-pointer focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-1 rounded", children: translate('common.remove', { defaultValue: 'Remove' }) })] })), !isReadonly && touched && error.length > 0 && jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] })] })) : !isReadonly ? (jsxRuntimeExports.jsxs("div", { className: "w-full min-w-0", children: [jsxRuntimeExports.jsxs("button", { type: "button", disabled: !isEnabled, onClick: openLookup, title: actionLabel, className: `flex items-center gap-2 w-full sm:w-[180px] max-w-full px-3 h-[30px] text-sm border rounded-[10px] shadow-sm transition-colors ${hasError ? 'border-red-500 text-gray-700' : 'border-gray-300 text-gray-700'} ${!isEnabled ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-white cursor-pointer'}`, children: [jsxRuntimeExports.jsx("img", { src: img$g, alt: "", className: "w-4 h-4 opacity-50 flex-shrink-0" }), jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate", children: actionLabel }), isRequired && jsxRuntimeExports.jsx("span", { className: "shrink-0 text-red-500", children: "*" })] }), touched && error.length > 0 && jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] })] })) : null, !isReadonly && isOpen && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50", style: { backgroundColor: 'rgba(0,0,0,0.5)' }, onClick: () => { setIsOpen(false); onBlur(); } }), jsxRuntimeExports.jsxs("div", { className: "flex flex-col overflow-hidden", style: {
12351
+ position: 'fixed',
12352
+ top: modalPos.y,
12353
+ left: modalPos.x,
12354
+ width: modalSize.w,
12355
+ height: modalSize.h,
12356
+ zIndex: 51,
12357
+ resize: 'both',
12358
+ minWidth: 340,
12359
+ minHeight: 260,
12360
+ maxWidth: '96vw',
12361
+ maxHeight: '92vh',
12362
+ backgroundColor: 'var(--owt-color-bg, #FFFFFF)',
12363
+ borderRadius: 'var(--owt-widget-card-border-radius, 20px)',
12364
+ boxShadow: '0 24px 64px rgba(0,0,0,0.28)',
12365
+ }, onClick: (e) => e.stopPropagation(), children: [jsxRuntimeExports.jsxs("div", { onMouseDown: (e) => {
12366
+ e.preventDefault();
12367
+ isDragging.current = true;
12368
+ dragOrigin.current = { mouseX: e.clientX, mouseY: e.clientY, posX: modalPos.x, posY: modalPos.y };
12369
+ }, className: "flex items-center justify-between px-5 py-4 flex-shrink-0 select-none border-b border-gray-200 cursor-grab", children: [jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: translate('common.selectTitle', { label, defaultValue: `Select ${label}` }) }), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => { setIsOpen(false); onBlur(); }, onMouseDown: (e) => e.stopPropagation(), className: "p-0 border-0 bg-transparent cursor-pointer", "aria-label": translate('common.close', { defaultValue: 'Close' }), children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "", className: "w-5 h-5 opacity-60" }) })] }), jsxRuntimeExports.jsx("div", { className: "px-5 py-3 flex-shrink-0 border-b border-gray-200", children: jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-3 h-[30px] border border-gray-300 rounded-[10px] bg-white", children: [jsxRuntimeExports.jsx("input", { ref: searchInputRef, type: "text", value: searchText, onChange: (e) => setSearchText(e.target.value), onKeyDown: (e) => {
12370
+ if (e.key === 'Enter') {
12371
+ e.preventDefault();
12372
+ runSearch(searchText, 1);
12373
+ }
12374
+ }, placeholder: searchPlaceholder, className: "flex-1 outline-none text-sm text-gray-900 bg-transparent" }), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => runSearch(searchText, 1), "aria-label": translate('common.search', { defaultValue: 'Search' }), className: "flex-shrink-0 p-0 border-0 bg-transparent cursor-pointer", children: jsxRuntimeExports.jsx("img", { src: img$g, alt: "", className: "w-4 h-4 opacity-40" }) })] }) }), jsxRuntimeExports.jsx("div", { className: "overflow-auto flex-1", children: searchResults.length === 0 ? (jsxRuntimeExports.jsx("p", { className: "text-center text-sm text-gray-500 py-10", children: searchText
12375
+ ? translate('common.noResults', { defaultValue: 'No results found' })
12376
+ : translate('common.searchHint', { defaultValue: 'Type and press Enter or click search' }) })) : (jsxRuntimeExports.jsx(ResultsTable, { rows: searchResults, selectedRowKey: pendingRow?.internal_record_id ?? null, onRowClick: setPendingRow, onRowDoubleClick: applySelection })) }), jsxRuntimeExports.jsxs("div", { className: `flex-shrink-0 flex flex-wrap items-center gap-3 px-5 py-3 border-t border-gray-200 ${totalCount !== null ? 'justify-between' : 'justify-end'}`, children: [totalCount !== null && (jsxRuntimeExports.jsx(PaginationFooter, { embedded: true, currentPage: currentPage, totalPages: totalPages, totalCount: totalCount, pageSize: pageSize, onPageChange: (page) => runSearch(searchText, page), onPrev: () => currentPage > 1 && runSearch(searchText, currentPage - 1), onNext: () => currentPage < totalPages && runSearch(searchText, currentPage + 1), translate: translate })), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => pendingRow && applySelection(pendingRow), disabled: !pendingRow, className: "px-4 h-9 text-sm font-medium rounded-[10px] text-white disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0", style: { backgroundColor: 'var(--owt-color-info, #2563eb)' }, children: selectRecordLabel })] })] })] }))] }));
12377
+ };
12378
+
12379
+ const MultiSelectWidget = ({ config }) => {
12380
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
12381
+ const { translate, translateConfig } = useWidgetTranslation();
12382
+ const [isOpen, setIsOpen] = React.useState(false);
12383
+ const [isListPopupOpen, setIsListPopupOpen] = React.useState(false);
12384
+ const [searchQuery, setSearchQuery] = React.useState('');
12385
+ const [dropdownPosition, setDropdownPosition] = React.useState(null);
12386
+ const [listPopupPosition, setListPopupPosition] = React.useState(null);
12387
+ const [mounted, setMounted] = React.useState(false);
12388
+ const containerRef = React.useRef(null);
12389
+ const triggerRef = React.useRef(null);
12390
+ const dropdownRef = React.useRef(null);
12391
+ const listPopupRef = React.useRef(null);
12392
+ const moreButtonRef = React.useRef(null);
12393
+ const searchInputRef = React.useRef(null);
12394
+ const formatConfig = widgetConfig['widget-data-format'];
12395
+ const sortOptions = formatConfig?.sortOptions ?? false;
12396
+ React.useEffect(() => {
12397
+ setMounted(true);
12398
+ }, []);
12399
+ const updateDropdownPosition = React.useCallback(() => {
12400
+ const trigger = triggerRef.current;
12401
+ if (!trigger)
12402
+ return;
12403
+ const rect = trigger.getBoundingClientRect();
12404
+ const gap = 4;
12405
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
12406
+ const spaceAbove = rect.top - gap;
12407
+ const openDown = spaceBelow >= 160 || spaceBelow >= spaceAbove;
12408
+ const availableSpace = openDown ? spaceBelow : spaceAbove;
12409
+ const maxHeight = Math.min(320, Math.max(160, availableSpace - 8));
12410
+ setDropdownPosition(openDown
12411
+ ? {
12412
+ top: rect.bottom + gap,
12413
+ left: rect.left,
12414
+ width: rect.width,
12415
+ maxHeight,
12416
+ placement: 'bottom',
12417
+ }
12418
+ : {
12419
+ bottom: window.innerHeight - rect.top + gap,
12420
+ left: rect.left,
12421
+ width: rect.width,
12422
+ maxHeight,
12423
+ placement: 'top',
12424
+ });
12425
+ }, []);
12426
+ const updateListPopupPosition = React.useCallback(() => {
12427
+ const anchor = moreButtonRef.current;
12428
+ if (!anchor)
12429
+ return;
12430
+ const rect = anchor.getBoundingClientRect();
12431
+ const gap = 4;
12432
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
12433
+ const spaceAbove = rect.top - gap;
12434
+ const openDown = spaceBelow >= 120 || spaceBelow >= spaceAbove;
12435
+ const availableSpace = openDown ? spaceBelow : spaceAbove;
12436
+ const maxHeight = Math.min(280, Math.max(120, availableSpace - 8));
12437
+ setListPopupPosition(openDown
12438
+ ? {
12439
+ top: rect.bottom + gap,
12440
+ left: rect.left,
12441
+ width: Math.max(rect.width, 220),
12442
+ maxHeight,
12443
+ placement: 'bottom',
12444
+ }
12445
+ : {
12446
+ bottom: window.innerHeight - rect.top + gap,
12447
+ left: rect.left,
12448
+ width: Math.max(rect.width, 220),
12449
+ maxHeight,
12450
+ placement: 'top',
12451
+ });
12452
+ }, []);
12453
+ React.useEffect(() => {
12454
+ if (!isOpen) {
12455
+ setDropdownPosition(null);
12456
+ setSearchQuery('');
12457
+ return;
12458
+ }
12459
+ updateDropdownPosition();
12460
+ const handleResize = () => updateDropdownPosition();
12461
+ window.addEventListener('resize', handleResize);
12462
+ return () => {
12463
+ window.removeEventListener('resize', handleResize);
12464
+ };
12465
+ }, [isOpen, updateDropdownPosition]);
12466
+ React.useEffect(() => {
12467
+ if (!isListPopupOpen) {
12468
+ setListPopupPosition(null);
12469
+ return;
12470
+ }
12471
+ updateListPopupPosition();
12472
+ const handleResize = () => updateListPopupPosition();
12473
+ window.addEventListener('resize', handleResize);
12474
+ return () => {
12475
+ window.removeEventListener('resize', handleResize);
12476
+ };
12477
+ }, [isListPopupOpen, updateListPopupPosition]);
12478
+ React.useEffect(() => {
12479
+ if (!isOpen && !isListPopupOpen)
12480
+ return;
12481
+ const handleScroll = (event) => {
12482
+ const target = event.target;
12483
+ if (dropdownRef.current?.contains(target))
12484
+ return;
12485
+ if (listPopupRef.current?.contains(target))
12486
+ return;
12487
+ if (isOpen)
12488
+ setIsOpen(false);
12489
+ if (isListPopupOpen)
12490
+ setIsListPopupOpen(false);
12491
+ };
12492
+ window.addEventListener('scroll', handleScroll, true);
12493
+ return () => window.removeEventListener('scroll', handleScroll, true);
12494
+ }, [isOpen, isListPopupOpen]);
12495
+ React.useEffect(() => {
12496
+ if (!isOpen && !isListPopupOpen)
12497
+ return;
12498
+ const handleClickOutside = (event) => {
12499
+ const target = event.target;
12500
+ if (isOpen) {
12501
+ if (containerRef.current?.contains(target))
12502
+ return;
12503
+ if (dropdownRef.current?.contains(target))
12504
+ return;
12505
+ setIsOpen(false);
12506
+ }
12507
+ if (isListPopupOpen) {
12508
+ if (listPopupRef.current?.contains(target))
12509
+ return;
12510
+ if (moreButtonRef.current?.contains(target))
12511
+ return;
12512
+ setIsListPopupOpen(false);
12513
+ }
12514
+ };
12515
+ document.addEventListener('mousedown', handleClickOutside);
12516
+ return () => document.removeEventListener('mousedown', handleClickOutside);
12517
+ }, [isOpen, isListPopupOpen]);
12518
+ React.useEffect(() => {
12519
+ if (isOpen && searchInputRef.current) {
12520
+ searchInputRef.current.focus();
12521
+ }
12522
+ }, [isOpen]);
12523
+ const processedOptions = React.useMemo(() => {
12524
+ let options = dataSourceOptions.map((opt) => {
12525
+ const rawLabel = String(opt.label ?? opt.value ?? '');
12526
+ return {
12527
+ value: opt.value,
12528
+ label: translateConfig(rawLabel),
12529
+ rawLabel,
12530
+ };
12531
+ });
12532
+ if (sortOptions) {
12533
+ options.sort((a, b) => a.label.localeCompare(b.label));
12534
+ }
12535
+ return options;
12536
+ }, [dataSourceOptions, sortOptions, translateConfig]);
12537
+ const filteredOptions = React.useMemo(() => {
12538
+ if (!searchQuery.trim())
12539
+ return processedOptions;
12540
+ const q = searchQuery.trim().toLowerCase();
12541
+ return processedOptions.filter((opt) => opt.label.toLowerCase().includes(q) ||
12542
+ opt.rawLabel.toLowerCase().includes(q));
12543
+ }, [processedOptions, searchQuery]);
12544
+ const selectedValues = React.useMemo(() => {
12545
+ if (value === null || value === undefined)
12546
+ return [];
12547
+ if (Array.isArray(value))
12548
+ return value;
12549
+ return [value];
12550
+ }, [value]);
12551
+ const allFilteredSelected = React.useMemo(() => {
12552
+ if (filteredOptions.length === 0)
12553
+ return false;
12554
+ return filteredOptions.every((opt) => selectedValues.includes(opt.value));
12555
+ }, [filteredOptions, selectedValues]);
12556
+ const handleToggle = React.useCallback((optionValue, checked) => {
12557
+ if (checked) {
12558
+ onChange([...selectedValues, optionValue]);
12559
+ }
12560
+ else {
12561
+ onChange(selectedValues.filter((v) => v !== optionValue));
12562
+ }
12563
+ }, [selectedValues, onChange]);
12564
+ const handleSelectAll = React.useCallback(() => {
12565
+ const filteredVals = filteredOptions.map((o) => o.value);
12566
+ const merged = Array.from(new Set([...selectedValues, ...filteredVals]));
12567
+ onChange(merged);
12568
+ }, [filteredOptions, selectedValues, onChange]);
12569
+ const handleClearAll = React.useCallback(() => {
12570
+ onChange([]);
12571
+ }, [onChange]);
12572
+ const selectedLabels = React.useMemo(() => {
12573
+ return selectedValues.map((val) => {
12574
+ const opt = processedOptions.find((o) => o.value === val);
12575
+ return opt ? opt.label : translateConfig(String(val));
12576
+ });
12577
+ }, [selectedValues, processedOptions, translateConfig]);
12578
+ const fullSelectionText = selectedLabels.join(', ');
12579
+ const visibleLabels = selectedLabels.slice(0, 5);
12580
+ const overflowCount = Math.max(0, selectedLabels.length - 10);
12581
+ const disabled = !isEnabled || loading || widgetConfig['widget-readonly'];
12582
+ const renderSelectedLabels = (options) => {
12583
+ if (selectedLabels.length === 0)
12584
+ return null;
12585
+ const readonly = options?.readonly ?? false;
12586
+ return (jsxRuntimeExports.jsxs("div", { className: `flex flex-wrap gap-1 ${readonly ? '' : 'mt-1.5'}`, children: [visibleLabels.map((label, index) => (jsxRuntimeExports.jsxs("span", { className: "inline-flex max-w-full items-center gap-1 rounded-md bg-blue-50 px-2 py-0.5 text-xs text-blue-800", title: label, children: [jsxRuntimeExports.jsx("span", { className: "truncate", children: label }), !readonly && !disabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleToggle(selectedValues[index], false), className: "shrink-0 text-blue-600 hover:text-blue-900 focus:outline-none", "aria-label": translate('common.removeItem', {
12587
+ label,
12588
+ defaultValue: `Remove ${label}`,
12589
+ }), children: "\u00D7" }))] }, `${selectedValues[index]}-${label}`))), overflowCount > 0 && (jsxRuntimeExports.jsx("button", { ref: moreButtonRef, type: "button", onClick: () => setIsListPopupOpen((prev) => !prev), className: "inline-flex items-center rounded-md bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-1 focus:ring-blue-500", children: translate('common.moreSelected', {
12590
+ count: overflowCount,
12591
+ defaultValue: `+${overflowCount} more`,
12592
+ }) }))] }));
12593
+ };
12594
+ const listPopupPanel = isListPopupOpen && listPopupPosition && mounted ? (jsxRuntimeExports.jsxs("div", { ref: listPopupRef, className: "fixed z-[201] bg-white border border-gray-300 shadow-lg", style: {
12595
+ ...(listPopupPosition.placement === 'bottom'
12596
+ ? { top: listPopupPosition.top }
12597
+ : { bottom: listPopupPosition.bottom }),
12598
+ left: listPopupPosition.left,
12599
+ width: listPopupPosition.width,
12600
+ maxWidth: '320px',
12601
+ maxHeight: listPopupPosition.maxHeight,
12602
+ borderRadius: '10px',
12603
+ display: 'flex',
12604
+ flexDirection: 'column',
12605
+ }, children: [jsxRuntimeExports.jsx("div", { className: "px-3 py-2 text-xs font-semibold text-gray-500 shrink-0", style: { borderBottom: '1px solid #e5e7eb' }, children: translate('common.allSelected', {
12606
+ count: selectedLabels.length,
12607
+ defaultValue: `All selected (${selectedLabels.length})`,
12608
+ }) }), jsxRuntimeExports.jsx("div", { className: "overflow-y-auto flex-1 min-h-0 py-1 overscroll-contain", children: selectedLabels.map((label, index) => (jsxRuntimeExports.jsx("div", { className: "px-3 py-1.5 text-sm text-gray-700", title: label, children: label }, `${selectedValues[index]}-${label}`))) })] })) : null;
12609
+ if (widgetConfig['widget-readonly']) {
12610
+ const fieldLabel = widgetConfig['widget-label'];
12611
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] MultiSelectDisplayWidget flex flex-col sm:flex-row sm:items-start", children: [fieldLabel && (jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", label: fieldLabel })), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [selectedLabels.length === 0 ? (jsxRuntimeExports.jsx("div", { className: "text-base text-gray-900 font-medium", children: "-" })) : (renderSelectedLabels({ readonly: true })), mounted && listPopupPanel && typeof document !== 'undefined'
12612
+ ? reactDom.createPortal(listPopupPanel, document.body)
12613
+ : null] })] }));
12614
+ }
12615
+ const optionsMaxHeight = dropdownPosition
12616
+ ? Math.min(280, dropdownPosition.maxHeight - 100)
12617
+ : 280;
12618
+ const dropdownPanel = isOpen && dropdownPosition && mounted ? (jsxRuntimeExports.jsxs("div", { ref: dropdownRef, className: "fixed z-[200] bg-white border border-gray-300 shadow-lg", style: {
12619
+ ...(dropdownPosition.placement === 'bottom'
12620
+ ? { top: dropdownPosition.top }
12621
+ : { bottom: dropdownPosition.bottom }),
12622
+ left: dropdownPosition.left,
12623
+ width: dropdownPosition.width,
12624
+ maxWidth: '280px',
12625
+ maxHeight: dropdownPosition.maxHeight,
12626
+ borderRadius: '10px',
12627
+ display: 'flex',
12628
+ flexDirection: 'column',
12629
+ }, children: [jsxRuntimeExports.jsx("div", { className: "px-3 pt-2 pb-1 shrink-0", style: { borderBottom: '1px solid #e5e7eb' }, children: jsxRuntimeExports.jsx("input", { ref: searchInputRef, type: "text", placeholder: translate('common.searchPlaceholder', { defaultValue: 'Search...' }), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "w-full h-[28px] px-2 text-sm border border-gray-300 bg-gray-50 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500", style: { borderRadius: '6px' } }) }), jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-3 py-1 shrink-0", style: { borderBottom: '1px solid #e5e7eb' }, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: allFilteredSelected ? () => {
12630
+ const filteredVals = new Set(filteredOptions.map((o) => o.value));
12631
+ onChange(selectedValues.filter((v) => !filteredVals.has(v)));
12632
+ } : handleSelectAll, className: "text-xs font-medium text-blue-600 hover:text-blue-800 focus:outline-none", children: allFilteredSelected
12633
+ ? translate('common.deselectAll', { defaultValue: 'Deselect All' })
12634
+ : translate('common.selectAll', { defaultValue: 'Select All' }) }), selectedValues.length > 0 && (jsxRuntimeExports.jsx("button", { type: "button", onClick: handleClearAll, className: "text-xs font-medium text-red-500 hover:text-red-700 focus:outline-none", children: translate('common.clearAll', { defaultValue: 'Clear All' }) }))] }), jsxRuntimeExports.jsx("div", { className: "overflow-y-auto flex-1 min-h-0 py-1 overscroll-contain", style: { maxHeight: `${Math.max(80, optionsMaxHeight)}px` }, children: loading ? (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500 px-3 py-2", children: translate('common.loading') })) : filteredOptions.length === 0 ? (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-400 px-3 py-2", children: translate('common.noOptionsFound', { defaultValue: 'No options found' }) })) : (filteredOptions.map((option) => {
12635
+ const isChecked = selectedValues.includes(option.value);
12636
+ return (jsxRuntimeExports.jsxs("label", { className: `flex items-center gap-2 px-3 py-1 cursor-pointer hover:bg-blue-50 ${isChecked ? 'bg-blue-50/60' : ''}`, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => handleToggle(option.value, e.target.checked), className: "h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700 leading-normal select-none", children: option.label })] }, option.value));
12637
+ })) })] })) : null;
12638
+ return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsx(WidgetFieldLabel, { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", label: widgetConfig['widget-label'] ?? '', required: isRequired }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", ref: containerRef, children: [jsxRuntimeExports.jsxs("button", { ref: triggerRef, type: "button", onClick: () => {
12639
+ if (!disabled)
12640
+ setIsOpen((prev) => !prev);
12641
+ }, onBlur: () => {
12642
+ if (!isOpen)
12643
+ onBlur();
12644
+ }, disabled: disabled, className: `w-full sm:w-[280px] max-w-full h-[30px] px-3 border shadow-sm text-left flex items-center justify-between gap-2 ${(touched && error.length > 0) ||
12645
+ (widgetConfig['widget-required'] && selectedValues.length === 0)
12646
+ ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
12647
+ : 'border-gray-300'} ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white cursor-pointer'} focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500`, style: { borderRadius: '10px' }, title: selectedValues.length > 0
12648
+ ? fullSelectionText
12649
+ : translateConfig(widgetConfig['widget-data-tooltip']), children: [jsxRuntimeExports.jsx("span", { className: `truncate text-sm ${selectedValues.length === 0 ? 'text-gray-400' : 'text-gray-900'}`, children: selectedLabels.length === 0
12650
+ ? translate('common.select', { defaultValue: 'Select...' })
12651
+ : translate('common.selectedCount', {
12652
+ count: selectedLabels.length,
12653
+ defaultValue: `${selectedLabels.length} selected`,
12654
+ }) }), jsxRuntimeExports.jsx("svg", { className: `w-4 h-4 flex-shrink-0 text-gray-500 transition-transform ${isOpen ? 'rotate-180' : ''}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] }), mounted && dropdownPanel && typeof document !== 'undefined'
12655
+ ? reactDom.createPortal(dropdownPanel, document.body)
12656
+ : null, selectedLabels.length > 0 && renderSelectedLabels(), mounted && listPopupPanel && typeof document !== 'undefined'
12657
+ ? reactDom.createPortal(listPopupPanel, document.body)
12658
+ : null, touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] })), loading && (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500 mt-1", children: translate('common.loadingOptions') }))] })] }) }));
12659
+ };
12660
+
11562
12661
  /**
11563
12662
  * Register all default/generic widgets
11564
12663
  * This is called automatically when the package is imported
@@ -11606,6 +12705,10 @@ const registerDefaultWidgets = () => {
11606
12705
  widgetRegistry.register({ widget: 'scores-display', component: ScoresDisplayWidget });
11607
12706
  // ID Authentication widget for OIDC-based foundational ID authentication (view-only + action)
11608
12707
  widgetRegistry.register({ widget: 'id-authentication', component: IdAuthenticationWidget });
12708
+ // Register lookup widget — searchable popup to select a record from any register
12709
+ widgetRegistry.register({ widget: 'register-lookup', component: RegisterLookupWidget });
12710
+ // Multi-select widget — searchable dropdown with checkbox-style options, select all, and clear all
12711
+ widgetRegistry.register({ widget: 'multi-select', component: MultiSelectWidget });
11609
12712
  };
11610
12713
  // Auto-register on import
11611
12714
  registerDefaultWidgets();
@@ -11668,6 +12771,27 @@ var enTranslations = {
11668
12771
  "common.sectionSaved": "Saved",
11669
12772
  "common.sectionModified": "Modified and not saved",
11670
12773
  "common.supportedDocuments": "Supported Documents",
12774
+ "common.searchPlaceholder": "Search...",
12775
+ "common.selectAll": "Select All",
12776
+ "common.deselectAll": "Deselect All",
12777
+ "common.clearAll": "Clear All",
12778
+ "common.noOptionsFound": "No options found",
12779
+ "common.allSelected": "All selected ({{count}})",
12780
+ "common.moreSelected": "+{{count}} more",
12781
+ "common.selectedCount": "{{count}} selected",
12782
+ "common.removeItem": "Remove {{label}}",
12783
+ "common.selectAction": "Select {{label}}",
12784
+ "common.selectTitle": "Select {{label}}",
12785
+ "common.change": "Change",
12786
+ "common.noResults": "No results found",
12787
+ "common.searchHint": "Type and press Enter or click search",
12788
+ "common.record": "{{count}} record",
12789
+ "common.records": "{{count}} records",
12790
+ "common.page": "Page",
12791
+ "common.ofPages": "of {{total}}",
12792
+ "common.pageNumber": "Page number",
12793
+ "common.close": "Close",
12794
+ "common.search": "Search",
11671
12795
  "table.addRecord": "Add New Record",
11672
12796
  "table.confirm": "Confirm Action",
11673
12797
  "table.discard": "Discard & Continue",
@@ -11908,13 +13032,10 @@ const translateWidgetConfig = (widgetConfig, translate) => {
11908
13032
  ...dataSource,
11909
13033
  options: dataSource.options.map((option) => {
11910
13034
  if (option.label && typeof option.label === 'string') {
11911
- const optionLabel = option.label;
11912
- if (isTranslationKey(optionLabel)) {
11913
- return {
11914
- ...option,
11915
- label: translate(optionLabel, { defaultValue: optionLabel }),
11916
- };
11917
- }
13035
+ return {
13036
+ ...option,
13037
+ label: translate(option.label, { defaultValue: option.label }),
13038
+ };
11918
13039
  }
11919
13040
  return option;
11920
13041
  }),
@@ -11982,12 +13103,14 @@ exports.HeaderSectionWidget = HeaderSectionWidget;
11982
13103
  exports.IdAuthenticationWidget = IdAuthenticationWidget;
11983
13104
  exports.IterableAccordionWidget = IterableAccordionWidget;
11984
13105
  exports.JSONEditorPanel = JSONEditorPanel;
13106
+ exports.MultiSelectWidget = MultiSelectWidget;
11985
13107
  exports.NumberInputWidget = NumberInputWidget;
11986
13108
  exports.PanelRenderer = PanelRenderer;
11987
13109
  exports.PhoneInputWidget = PhoneInputWidget;
11988
13110
  exports.ProfileWidget = ProfileWidget;
11989
13111
  exports.PropertyEditor = PropertyEditor;
11990
13112
  exports.RadioWidget = RadioWidget;
13113
+ exports.RegisterLookupWidget = RegisterLookupWidget;
11991
13114
  exports.ScoresDisplayWidget = ScoresDisplayWidget;
11992
13115
  exports.SectionBuilder = SectionBuilder;
11993
13116
  exports.SectionRenderer = SectionRenderer;
@@ -12006,10 +13129,13 @@ exports.applyCaseControl = applyCaseControl;
12006
13129
  exports.applyDecimalPrecision = applyDecimalPrecision;
12007
13130
  exports.applyMask = applyMask;
12008
13131
  exports.applySharedGeoHierarchyToValues = applySharedGeoHierarchyToValues;
13132
+ exports.collectGeoWidgetRegistrationsFromWidgets = collectGeoWidgetRegistrationsFromWidgets;
13133
+ exports.createGeoLevelMnemonicResolver = createGeoLevelMnemonicResolver;
12009
13134
  exports.createWidgetStore = createWidgetStore;
12010
13135
  exports.createZodSchema = createZodSchema;
12011
13136
  exports.defaultTheme = defaultTheme;
12012
13137
  exports.evaluateCondition = evaluateCondition;
13138
+ exports.evaluateWidgetConditions = evaluateWidgetConditions;
12013
13139
  exports.filterByCharacterType = filterByCharacterType;
12014
13140
  exports.formatCurrency = formatCurrency;
12015
13141
  exports.formatDate = formatDate;
@@ -12018,23 +13144,34 @@ exports.formatPhone = formatPhone;
12018
13144
  exports.formatValue = formatValue;
12019
13145
  exports.geoHierarchyBuilder = geoHierarchyBuilder;
12020
13146
  exports.getApiDataSource = getApiDataSource;
13147
+ exports.getCachedApiDataSource = getCachedApiDataSource;
12021
13148
  exports.getFormattedNumberLength = getFormattedNumberLength;
13149
+ exports.getGeoDescendantWidgetIds = getGeoDescendantWidgetIds;
13150
+ exports.getGeoGroupId = getGeoGroupId;
13151
+ exports.getGeoWidgetRegistrationsInGroup = getGeoWidgetRegistrationsInGroup;
12022
13152
  exports.getSchemaDataSource = getSchemaDataSource;
12023
13153
  exports.getStaticDataSource = getStaticDataSource;
12024
13154
  exports.getValueByPath = getValueByPath;
12025
13155
  exports.getWidgetValue = getWidgetValue;
13156
+ exports.hasVisibilityRules = hasVisibilityRules;
12026
13157
  exports.initI18n = initI18n;
12027
13158
  exports.isAllowedKey = isAllowedKey;
12028
13159
  exports.isUpstreamGeoAncestor = isUpstreamGeoAncestor;
12029
13160
  exports.normalizeNumericDefault = normalizeNumericDefault;
13161
+ exports.normalizeOptionRules = normalizeOptionRules;
13162
+ exports.orderGeoWidgetRegistrations = orderGeoWidgetRegistrations;
12030
13163
  exports.parseDataPath = parseDataPath;
12031
13164
  exports.parseNumber = parseNumber;
13165
+ exports.rebuildGeoHierarchyFromRegistrations = rebuildGeoHierarchyFromRegistrations;
13166
+ exports.reconcileGeoHierarchiesInValues = reconcileGeoHierarchiesInValues;
12032
13167
  exports.registerDefaultWidgets = registerDefaultWidgets;
13168
+ exports.registerGeoWidget = registerGeoWidget;
12033
13169
  exports.registerGeoWidgetParent = registerGeoWidgetParent;
12034
13170
  exports.removeMask = removeMask;
12035
13171
  exports.resetAll = resetAll;
12036
13172
  exports.resetAndSeedGeoHierarchyFromValues = resetAndSeedGeoHierarchyFromValues;
12037
13173
  exports.resetWidget = resetWidget;
13174
+ exports.resolveGeoWidgetLevelLabel = resolveGeoWidgetLevelLabel;
12038
13175
  exports.resolveGeoWidgetLevelValue = resolveGeoWidgetLevelValue;
12039
13176
  exports.resolveTheme = resolveTheme;
12040
13177
  exports.resolveWidgetIdValue = resolveWidgetIdValue;
@@ -12048,11 +13185,13 @@ exports.setValueByPath = setValueByPath;
12048
13185
  exports.setValues = setValues;
12049
13186
  exports.setWidgetValue = setWidgetValue;
12050
13187
  exports.shouldEnableWidget = shouldEnableWidget;
13188
+ exports.shouldRequireWidget = shouldRequireWidget;
12051
13189
  exports.shouldShowWidget = shouldShowWidget;
12052
13190
  exports.transformDataSourceOptions = transformDataSourceOptions;
12053
13191
  exports.translatePanelConfig = translatePanelConfig;
12054
13192
  exports.translateUISchema = translateUISchema;
12055
13193
  exports.translateWidgetConfig = translateWidgetConfig;
13194
+ exports.unregisterGeoWidget = unregisterGeoWidget;
12056
13195
  exports.unregisterGeoWidgetParent = unregisterGeoWidgetParent;
12057
13196
  exports.useBaseWidget = useBaseWidget;
12058
13197
  exports.useGeoWidgetCascade = useGeoWidgetCascade;