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