@openg2p/registry-widgets 1.1.2-dev.5 → 1.1.2-dev.7

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 (45) hide show
  1. package/dist/components/SectionBuilder/schemas.d.ts +112 -0
  2. package/dist/components/SectionBuilder/schemas.d.ts.map +1 -1
  3. package/dist/components/SectionRenderer.d.ts.map +1 -1
  4. package/dist/components/WidgetFieldLabel.d.ts +11 -0
  5. package/dist/components/WidgetFieldLabel.d.ts.map +1 -0
  6. package/dist/hooks/useBaseWidget.d.ts +2 -0
  7. package/dist/hooks/useBaseWidget.d.ts.map +1 -1
  8. package/dist/index.d.ts +45 -13
  9. package/dist/index.esm.js +878 -258
  10. package/dist/index.esm.js.map +1 -1
  11. package/dist/index.js +885 -257
  12. package/dist/index.js.map +1 -1
  13. package/dist/registry/defaultWidgets.d.ts.map +1 -1
  14. package/dist/types/index.d.ts +11 -1
  15. package/dist/types/index.d.ts.map +1 -1
  16. package/dist/utils/conditions.d.ts +17 -11
  17. package/dist/utils/conditions.d.ts.map +1 -1
  18. package/dist/utils/geoHierarchy.d.ts +9 -0
  19. package/dist/utils/geoHierarchy.d.ts.map +1 -1
  20. package/dist/utils/schemaNamespace.d.ts.map +1 -1
  21. package/dist/utils/schemaTranslation.d.ts.map +1 -1
  22. package/dist/utils/sectionRevert.d.ts +24 -0
  23. package/dist/utils/sectionRevert.d.ts.map +1 -0
  24. package/dist/utils/sectionValidate.d.ts.map +1 -1
  25. package/dist/widgets/ArrayWidget.d.ts.map +1 -1
  26. package/dist/widgets/BooleanWidget.d.ts.map +1 -1
  27. package/dist/widgets/CheckboxWidget.d.ts.map +1 -1
  28. package/dist/widgets/CurrencyInputWidget.d.ts.map +1 -1
  29. package/dist/widgets/DateInputWidget.d.ts.map +1 -1
  30. package/dist/widgets/DateTimeInputWidget.d.ts.map +1 -1
  31. package/dist/widgets/DialogTableWidget.d.ts.map +1 -1
  32. package/dist/widgets/FileInputWidget.d.ts.map +1 -1
  33. package/dist/widgets/IterableAccordionWidget.d.ts.map +1 -1
  34. package/dist/widgets/MultiSelectWidget.d.ts +7 -0
  35. package/dist/widgets/MultiSelectWidget.d.ts.map +1 -0
  36. package/dist/widgets/NumberInputWidget.d.ts.map +1 -1
  37. package/dist/widgets/PhoneInputWidget.d.ts.map +1 -1
  38. package/dist/widgets/RadioWidget.d.ts.map +1 -1
  39. package/dist/widgets/RegisterLookupWidget.d.ts.map +1 -1
  40. package/dist/widgets/SelectWidget.d.ts.map +1 -1
  41. package/dist/widgets/TextAreaWidget.d.ts.map +1 -1
  42. package/dist/widgets/TextInputWidget.d.ts.map +1 -1
  43. package/dist/widgets/index.d.ts +1 -0
  44. package/dist/widgets/index.d.ts.map +1 -1
  45. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -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
@@ -1936,6 +1976,98 @@ const WidgetProvider = ({ store, dataSourceRequestHandler, schemaData, translate
1936
1976
  return content;
1937
1977
  };
1938
1978
 
1979
+ /**
1980
+ * Custom hook for widget translations
1981
+ * Provides translation function with widget-specific namespace and fallback support
1982
+ */
1983
+ const useWidgetTranslation = () => {
1984
+ const { translate: translateFunction } = useWidgetContext();
1985
+ /**
1986
+ * Translate a key with flexible namespace support
1987
+ * Supports translation keys in various formats and direct strings
1988
+ *
1989
+ * Translation key formats supported:
1990
+ * - "widgets:common.addItem" - Namespaced key (for widget-specific translations)
1991
+ * - "Name" - Direct string (will be looked up in flat translation structure)
1992
+ * - "sections.personalDetails" - Nested key (for backward compatibility)
1993
+ *
1994
+ * With flat translation structure, direct strings like "Name" are automatically
1995
+ * translated by looking them up in the translation resources.
1996
+ *
1997
+ * @param keyOrString - Translation key (e.g., "widgets:common.addItem") or direct string (e.g., "Name")
1998
+ * @param options - Translation options (interpolation values, default value, etc.)
1999
+ * @returns Translated string or original string if translation not found
2000
+ */
2001
+ const translate = (keyOrString, options) => {
2002
+ if (!keyOrString) {
2003
+ return options?.defaultValue || '';
2004
+ }
2005
+ // Use the provided translation function or fallback to the key
2006
+ if (translateFunction) {
2007
+ return translateFunction(keyOrString, options) || options?.defaultValue || keyOrString;
2008
+ }
2009
+ // Fallback to key if no translation function available
2010
+ return options?.defaultValue || keyOrString;
2011
+ };
2012
+ /**
2013
+ * Translate widget config property
2014
+ * Attempts to translate the value, but if translation is not found,
2015
+ * returns the original value as-is (graceful fallback)
2016
+ *
2017
+ * This function will:
2018
+ * - Try to translate any string value
2019
+ * - If translation exists, use the translated value
2020
+ * - If translation doesn't exist (returns same value or throws), use original value
2021
+ * - This prevents errors when literal strings like "XXXX-XXXX-XXXX" are used
2022
+ */
2023
+ const translateConfig = (value, fallback) => {
2024
+ if (!value) {
2025
+ return fallback || '';
2026
+ }
2027
+ // Try to translate the value
2028
+ if (translateFunction) {
2029
+ try {
2030
+ // Pass defaultValue to ensure we get the original value if translation fails
2031
+ const translated = translateFunction(value, { defaultValue: value });
2032
+ // If translation returns empty, null, undefined, or the exact same value,
2033
+ // it means no translation was found - return the original value
2034
+ if (!translated || translated === value) {
2035
+ return value;
2036
+ }
2037
+ // Translation found, return it
2038
+ return translated;
2039
+ }
2040
+ catch (error) {
2041
+ // If translation throws an error (e.g., missing key warning), return original value
2042
+ return value;
2043
+ }
2044
+ }
2045
+ // No translation function available, return value as-is
2046
+ return value;
2047
+ };
2048
+ // No need of this getLanguage and changeLanguage functions
2049
+ /**
2050
+ * Get current language
2051
+ */
2052
+ // const getLanguage = (): string => {
2053
+ // return i18n.language || 'en';
2054
+ // };
2055
+ /**
2056
+ * Change language
2057
+ */
2058
+ // const changeLanguage = (lng: string): Promise<void> => {
2059
+ // return i18n.changeLanguage(lng).then(() => undefined);
2060
+ // };
2061
+ return {
2062
+ t: translate,
2063
+ translate,
2064
+ translateConfig,
2065
+ // getLanguage,
2066
+ // changeLanguage,
2067
+ // i18n: null,
2068
+ };
2069
+ };
2070
+
1939
2071
  /**
1940
2072
  * Geo Hierarchy Builder
1941
2073
  * Manages geo hierarchy state and builds hierarchy JSON structure
@@ -2135,6 +2267,42 @@ function isUpstreamGeoAncestor(changedWidgetId, widgetId, immediateParentWidgetI
2135
2267
  }
2136
2268
  return false;
2137
2269
  }
2270
+ /** Group id for geo widgets sharing the same register prefix (e.g. `{registerId}`). */
2271
+ function getGeoGroupId(dataPath) {
2272
+ if (typeof dataPath === 'string' && dataPath.includes('.')) {
2273
+ return dataPath.split('.').slice(0, -1).join('.');
2274
+ }
2275
+ return 'default';
2276
+ }
2277
+ /**
2278
+ * Resolve the human-readable label for a geo level from persisted hierarchy JSON.
2279
+ * Used in readonly mode when API options are not loaded.
2280
+ */
2281
+ function resolveGeoWidgetLevelLabel(values, widgetId, dataPath, geoConfig) {
2282
+ if (!dataPath || typeof dataPath !== 'string') {
2283
+ return undefined;
2284
+ }
2285
+ const stored = getWidgetValue(values, dataPath, widgetId);
2286
+ const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
2287
+ if (!Array.isArray(hierarchy)) {
2288
+ return undefined;
2289
+ }
2290
+ const levelData = hierarchy.find((l) => l.level === geoConfig.level);
2291
+ if (levelData?.level_value_mnemonic) {
2292
+ return String(levelData.level_value_mnemonic);
2293
+ }
2294
+ return undefined;
2295
+ }
2296
+ /** All registered geo widgets that are descendants of ancestorWidgetId. */
2297
+ function getGeoDescendantWidgetIds(ancestorWidgetId) {
2298
+ const descendants = [];
2299
+ for (const [childId, parentId] of geoWidgetParentRegistry.entries()) {
2300
+ if (isUpstreamGeoAncestor(ancestorWidgetId, childId, parentId)) {
2301
+ descendants.push(childId);
2302
+ }
2303
+ }
2304
+ return descendants;
2305
+ }
2138
2306
  function readStoredHierarchyLevels(values, dataPath, widgetId) {
2139
2307
  const stored = getWidgetValue(values, dataPath, widgetId);
2140
2308
  const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
@@ -2185,6 +2353,7 @@ const useBaseWidget = (options) => {
2185
2353
  const dispatch = useDispatch();
2186
2354
  const context = useWidgetContext();
2187
2355
  const eventBus = useWidgetEventBus();
2356
+ const { translateConfig } = useWidgetTranslation();
2188
2357
  const widgetId = config['widget-id'];
2189
2358
  // Fall back to WidgetContext for dataSourceRequestHandler
2190
2359
  const dataSourceRequestHandler = propHandler || context.dataSourceRequestHandler;
@@ -2355,6 +2524,15 @@ const useBaseWidget = (options) => {
2355
2524
  }
2356
2525
  // eslint-disable-next-line react-hooks/exhaustive-deps
2357
2526
  }, [isLayoutWidget]); // Only run once on mount
2527
+ const resolveIsRequired = useCallback((currentValues) => {
2528
+ if (isLayoutWidget) {
2529
+ return false;
2530
+ }
2531
+ if (config['widget-readonly']) {
2532
+ return false;
2533
+ }
2534
+ return evaluateWidgetConditions(config['widget-data-options'], currentValues, config['widget-required'] ?? false).required;
2535
+ }, [config, isLayoutWidget]);
2358
2536
  // Handle value change
2359
2537
  // CRITICAL: Don't include 'values' in dependency array - it causes the callback to be recreated
2360
2538
  // every time values change, which can lead to stale closures and double dispatches
@@ -2398,29 +2576,26 @@ const useBaseWidget = (options) => {
2398
2576
  lastDispatchedValueRef.current = newValue;
2399
2577
  dispatch(setValue({ widgetId, value: newValue }));
2400
2578
  }
2579
+ else if (config['widget-geo-config']) {
2580
+ // Geo widgets: hierarchy dataPath is managed by useGeoWidgetCascade
2581
+ getGeoDescendantWidgetIds(widgetId).forEach((descendantId) => {
2582
+ dispatch(setValue({ widgetId: descendantId, value: GEO_LEVEL_CLEARED }));
2583
+ dispatch(setDataSource({ widgetId: descendantId, data: [] }));
2584
+ });
2585
+ dispatch(setValue({ widgetId, value: newValue }));
2586
+ }
2401
2587
  else {
2402
- // Has dataPath: update both widgetId and dataPath
2403
- // CRITICAL: For geo widgets, we do NOT want to overwrite the shared hierarchy dataPath
2404
- // with a primitive value (the selected ID). The hierarchy object is managed by useGeoWidgetCascade.
2405
- if (config['widget-geo-config']) {
2406
- dispatch(setValue({ widgetId, value: newValue }));
2407
- return;
2408
- }
2409
- // For non-geo widgets, update both widgetId and dataPath
2410
- // CRITICAL: Create updated values object with newValue already set
2411
- // This prevents setWidgetValue from reading stale values
2588
+ // Non-geo widgets: update both widgetId and dataPath
2412
2589
  const currentValuesWithUpdate = {
2413
2590
  ...valuesRef.current,
2414
- [widgetId]: newValue, // Ensure widgetId has the new value
2591
+ [widgetId]: newValue,
2415
2592
  };
2416
2593
  const updatedValues = setWidgetValue(currentValuesWithUpdate, config['widget-data-path'], widgetId, newValue);
2417
- // setWidgetValue returns the complete updated structure with all existing data preserved
2418
- // Use setValues to update the entire state with deep merge
2419
2594
  dispatch(setValues(updatedValues));
2420
2595
  }
2421
2596
  // Validate if needed
2422
2597
  if (validate) {
2423
- const validationErrors = validateWidget(newValue, config['widget-data-validation'], config['widget-required']);
2598
+ const validationErrors = validateWidget(newValue, config['widget-data-validation'], resolveIsRequired(currentValues));
2424
2599
  dispatch(setError({ widgetId, errors: validationErrors }));
2425
2600
  }
2426
2601
  // Call custom onChange if provided
@@ -2439,13 +2614,12 @@ const useBaseWidget = (options) => {
2439
2614
  timestamp: Date.now(),
2440
2615
  });
2441
2616
  }
2442
- }, [config, widgetId, dispatch, onValueChange, eventBus] // Removed 'values' to prevent stale closures
2617
+ }, [config, widgetId, dispatch, onValueChange, eventBus, resolveIsRequired] // Removed 'values' to prevent stale closures
2443
2618
  );
2444
2619
  // Handle blur
2445
2620
  const handleBlur = useCallback(() => {
2446
2621
  dispatch(setTouched({ widgetId, touched: true }));
2447
- // Validate on blur
2448
- const validationErrors = validateWidget(currentValue, config['widget-data-validation'], config['widget-required']);
2622
+ const validationErrors = validateWidget(currentValue, config['widget-data-validation'], resolveIsRequired(valuesRef.current));
2449
2623
  dispatch(setError({ widgetId, errors: validationErrors }));
2450
2624
  // Publish widget:blur event
2451
2625
  if (eventBus) {
@@ -2456,7 +2630,7 @@ const useBaseWidget = (options) => {
2456
2630
  timestamp: Date.now(),
2457
2631
  });
2458
2632
  }
2459
- }, [currentValue, config, widgetId, dispatch, eventBus]);
2633
+ }, [currentValue, config, widgetId, dispatch, eventBus, resolveIsRequired]);
2460
2634
  // Get field value helper
2461
2635
  const getFieldValue = useCallback((path) => {
2462
2636
  return getWidgetValue(values, path, '');
@@ -2464,7 +2638,7 @@ const useBaseWidget = (options) => {
2464
2638
  // Conditional visibility and enablement
2465
2639
  const isVisible = useMemo(() => {
2466
2640
  // Layout widgets are always visible unless explicitly hidden
2467
- if (isLayoutWidget && !config['widget-data-options']?.condition) {
2641
+ if (isLayoutWidget && !hasVisibilityRules(config['widget-data-options'])) {
2468
2642
  return true;
2469
2643
  }
2470
2644
  return shouldShowWidget(config['widget-data-options'], values);
@@ -2479,6 +2653,7 @@ const useBaseWidget = (options) => {
2479
2653
  }
2480
2654
  return shouldEnableWidget(config['widget-data-options'], values);
2481
2655
  }, [config['widget-readonly'], config['widget-data-options'], values, isLayoutWidget]);
2656
+ const isRequired = useMemo(() => resolveIsRequired(values), [resolveIsRequired, values]);
2482
2657
  // Format value for display
2483
2658
  const formattedValue = useMemo(() => {
2484
2659
  if (!config['widget-data-format']) {
@@ -2525,10 +2700,9 @@ const useBaseWidget = (options) => {
2525
2700
  if (!dataSource) {
2526
2701
  return;
2527
2702
  }
2528
- // For API data sources, check if widget is readonly
2529
- // According to PRD: "Level 1 geo widgets load on widget mount or when entering edit mode"
2530
- // So we should only load API data sources when widget is NOT readonly
2531
- if (dataSource.type === 'api' && isReadonly) {
2703
+ // Non-geo readonly widgets skip API loads. Geo widgets still load in readonly so
2704
+ // labels can be resolved and translated on initial page view (not only after Edit).
2705
+ if (dataSource.type === 'api' && isReadonly && !geoConfig) {
2532
2706
  return;
2533
2707
  }
2534
2708
  // For widgets with dependencies, check if dependency value exists
@@ -2622,15 +2796,24 @@ const useBaseWidget = (options) => {
2622
2796
  // Use configKey and dependencyValue to ensure effect runs only when relevant state changes
2623
2797
  // eslint-disable-next-line react-hooks/exhaustive-deps
2624
2798
  }, [configKey, dependencyValue, dataSourceRequestHandler, schemaData, widgetId, dispatch]);
2799
+ const geoDisplayLabel = useMemo(() => {
2800
+ if (!geoConfig) {
2801
+ return undefined;
2802
+ }
2803
+ const rawLabel = resolveGeoWidgetLevelLabel(values, widgetId, config['widget-data-path'], geoConfig);
2804
+ return rawLabel ? translateConfig(rawLabel) : undefined;
2805
+ }, [values, widgetId, config, geoConfig, translateConfig]);
2625
2806
  return {
2626
2807
  widgetId,
2627
2808
  value: currentValue,
2809
+ geoDisplayLabel,
2628
2810
  formattedValue,
2629
2811
  error: errors,
2630
2812
  touched,
2631
2813
  loading,
2632
2814
  isVisible,
2633
2815
  isEnabled,
2816
+ isRequired,
2634
2817
  onChange: handleChange,
2635
2818
  onBlur: handleBlur,
2636
2819
  setError: (errors) => dispatch(setError({ widgetId, errors })),
@@ -2721,6 +2904,7 @@ const useGeoWidgetCascade = (options) => {
2721
2904
  const valuesRef = useRef(values);
2722
2905
  const handlerRef = useRef(dataSourceRequestHandler);
2723
2906
  const lastCascadePublishRef = useRef(undefined);
2907
+ const lastDirectParentValueRef = useRef(undefined);
2724
2908
  // Keep refs updated
2725
2909
  useEffect(() => {
2726
2910
  valuesRef.current = values;
@@ -2790,6 +2974,13 @@ const useGeoWidgetCascade = (options) => {
2790
2974
  event.value === null ||
2791
2975
  event.value === '' ||
2792
2976
  event.value === GEO_LEVEL_CLEARED;
2977
+ const isFirstParentEvent = lastDirectParentValueRef.current === undefined;
2978
+ const parentValueChanged = !isFirstParentEvent &&
2979
+ lastDirectParentValueRef.current !== event.value;
2980
+ lastDirectParentValueRef.current = event.value;
2981
+ if (!parentCleared && !parentValueChanged && !isFirstParentEvent) {
2982
+ return;
2983
+ }
2793
2984
  let parentValue = event.value;
2794
2985
  if (!parentCleared && (parentValue === undefined || parentValue === null)) {
2795
2986
  parentValue = currentValues[parentWidgetId];
@@ -2897,17 +3088,7 @@ const useGeoWidgetCascade = (options) => {
2897
3088
  if (dataPath && geoHierarchyBuilder.buildHierarchyJson(groupId)) {
2898
3089
  dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
2899
3090
  }
2900
- // Notify descendants when this level changes via hierarchy/rehydration (handleChange may not run).
2901
- if (!isLastLevel && eventBus && lastCascadePublishRef.current !== level_value_id) {
2902
- lastCascadePublishRef.current = level_value_id;
2903
- eventBus.publish({
2904
- type: 'widget:change',
2905
- widgetId,
2906
- value: level_value_id,
2907
- timestamp: Date.now(),
2908
- });
2909
- }
2910
- }, [geoConfig, currentValue, widgetId, dataPath, dispatch, dataSourceOptions, eventBus, groupId]);
3091
+ }, [geoConfig, currentValue, widgetId, dataPath, dispatch, dataSourceOptions, groupId]);
2911
3092
  };
2912
3093
 
2913
3094
  class WidgetRegistry {
@@ -3032,98 +3213,6 @@ const WidgetRenderer = ({ config, dataSourceRequestHandler: propDataSourceReques
3032
3213
  return (jsxRuntimeExports.jsx("div", { className: "widget-container", "data-widget-id": widgetContext.widgetId, style: { marginBottom: 0 }, children: widgetRegistry.render(config, widgetContext, defaultComponent) }));
3033
3214
  };
3034
3215
 
3035
- /**
3036
- * Custom hook for widget translations
3037
- * Provides translation function with widget-specific namespace and fallback support
3038
- */
3039
- const useWidgetTranslation = () => {
3040
- const { translate: translateFunction } = useWidgetContext();
3041
- /**
3042
- * Translate a key with flexible namespace support
3043
- * Supports translation keys in various formats and direct strings
3044
- *
3045
- * Translation key formats supported:
3046
- * - "widgets:common.addItem" - Namespaced key (for widget-specific translations)
3047
- * - "Name" - Direct string (will be looked up in flat translation structure)
3048
- * - "sections.personalDetails" - Nested key (for backward compatibility)
3049
- *
3050
- * With flat translation structure, direct strings like "Name" are automatically
3051
- * translated by looking them up in the translation resources.
3052
- *
3053
- * @param keyOrString - Translation key (e.g., "widgets:common.addItem") or direct string (e.g., "Name")
3054
- * @param options - Translation options (interpolation values, default value, etc.)
3055
- * @returns Translated string or original string if translation not found
3056
- */
3057
- const translate = (keyOrString, options) => {
3058
- if (!keyOrString) {
3059
- return options?.defaultValue || '';
3060
- }
3061
- // Use the provided translation function or fallback to the key
3062
- if (translateFunction) {
3063
- return translateFunction(keyOrString, options) || options?.defaultValue || keyOrString;
3064
- }
3065
- // Fallback to key if no translation function available
3066
- return options?.defaultValue || keyOrString;
3067
- };
3068
- /**
3069
- * Translate widget config property
3070
- * Attempts to translate the value, but if translation is not found,
3071
- * returns the original value as-is (graceful fallback)
3072
- *
3073
- * This function will:
3074
- * - Try to translate any string value
3075
- * - If translation exists, use the translated value
3076
- * - If translation doesn't exist (returns same value or throws), use original value
3077
- * - This prevents errors when literal strings like "XXXX-XXXX-XXXX" are used
3078
- */
3079
- const translateConfig = (value, fallback) => {
3080
- if (!value) {
3081
- return fallback || '';
3082
- }
3083
- // Try to translate the value
3084
- if (translateFunction) {
3085
- try {
3086
- // Pass defaultValue to ensure we get the original value if translation fails
3087
- const translated = translateFunction(value, { defaultValue: value });
3088
- // If translation returns empty, null, undefined, or the exact same value,
3089
- // it means no translation was found - return the original value
3090
- if (!translated || translated === value) {
3091
- return value;
3092
- }
3093
- // Translation found, return it
3094
- return translated;
3095
- }
3096
- catch (error) {
3097
- // If translation throws an error (e.g., missing key warning), return original value
3098
- return value;
3099
- }
3100
- }
3101
- // No translation function available, return value as-is
3102
- return value;
3103
- };
3104
- // No need of this getLanguage and changeLanguage functions
3105
- /**
3106
- * Get current language
3107
- */
3108
- // const getLanguage = (): string => {
3109
- // return i18n.language || 'en';
3110
- // };
3111
- /**
3112
- * Change language
3113
- */
3114
- // const changeLanguage = (lng: string): Promise<void> => {
3115
- // return i18n.changeLanguage(lng).then(() => undefined);
3116
- // };
3117
- return {
3118
- t: translate,
3119
- translate,
3120
- translateConfig,
3121
- // getLanguage,
3122
- // changeLanguage,
3123
- // i18n: null,
3124
- };
3125
- };
3126
-
3127
3216
  /**
3128
3217
  * Renders a panel with its nested panels or widgets
3129
3218
  *
@@ -3242,6 +3331,16 @@ const PanelRenderer = ({ panel, dataSourceRequestHandler, schemaData, onValueCha
3242
3331
  return (jsxRuntimeExports.jsx("div", { className: `panel panel-${orientation}`, "data-panel-id": panel['panel-id'], style: orientation === 'horizontal' ? { width: '100%' } : {}, children: content }));
3243
3332
  };
3244
3333
 
3334
+ /**
3335
+ * Field label: long text truncates with ellipsis; required asterisk always stays visible.
3336
+ */
3337
+ const WidgetFieldLabel = ({ label, required = false, className = '', title, }) => {
3338
+ const { translateConfig } = useWidgetTranslation();
3339
+ const translatedLabel = translateConfig(label);
3340
+ const tooltip = title !== undefined ? translateConfig(title) : translatedLabel;
3341
+ 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: "*" })] }));
3342
+ };
3343
+
3245
3344
  /**
3246
3345
  * Utility functions for file preview functionality
3247
3346
  */
@@ -3591,7 +3690,7 @@ const deserializeValue = (value) => {
3591
3690
  };
3592
3691
 
3593
3692
  const FileInputWidget = ({ config }) => {
3594
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
3693
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
3595
3694
  const { translate, translateConfig } = useWidgetTranslation();
3596
3695
  const accept = widgetConfig['widget-data-options']?.accept;
3597
3696
  const multiple = widgetConfig['widget-data-options']?.multiple || false;
@@ -3831,7 +3930,7 @@ const FileInputWidget = ({ config }) => {
3831
3930
  setPreviewFile(null);
3832
3931
  } })] }));
3833
3932
  }
3834
- 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
3933
+ 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
3835
3934
  ? 'opacity-50 cursor-not-allowed'
3836
3935
  : ''}`, style: {
3837
3936
  width: '100%',
@@ -3892,6 +3991,13 @@ const namespaceWidgetConfig = (widgetConfig, namespace) => {
3892
3991
  if (namespaced['widget-data-path']) {
3893
3992
  namespaced['widget-data-path'] = namespaceDataPath(namespaced['widget-data-path'], namespace);
3894
3993
  }
3994
+ // Namespace geo parent references so cascade events match namespaced widget-id
3995
+ if (namespaced['widget-geo-config']?.parentWidgetId) {
3996
+ namespaced['widget-geo-config'] = {
3997
+ ...namespaced['widget-geo-config'],
3998
+ parentWidgetId: `${namespace}__${namespaced['widget-geo-config'].parentWidgetId}`,
3999
+ };
4000
+ }
3895
4001
  // Recursively namespace nested widgets (for layout widgets)
3896
4002
  if (namespaced.widgets && Array.isArray(namespaced.widgets)) {
3897
4003
  namespaced.widgets = namespaced.widgets.map((widget) => namespaceWidgetConfig(widget, namespace));
@@ -4096,6 +4202,9 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
4096
4202
  const isVisible = shouldShowWidget(widget['widget-data-options'], currentSchemaData);
4097
4203
  if (!isVisible)
4098
4204
  continue;
4205
+ const isEnabled = shouldEnableWidget(widget['widget-data-options'], currentSchemaData);
4206
+ if (!isEnabled)
4207
+ continue;
4099
4208
  const widgetId = widget['widget-id'];
4100
4209
  if (isTableLikeWidget(widget)) {
4101
4210
  const tableValid = validateTableLikeWidget(widget, currentSchemaData, dispatch, skipRequired);
@@ -4105,7 +4214,8 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
4105
4214
  continue;
4106
4215
  }
4107
4216
  const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
4108
- const errors = validateWidget(value, widget['widget-data-validation'], widget['widget-required'], skipRequired);
4217
+ const isRequired = shouldRequireWidget(widget['widget-data-options'], currentSchemaData, widget['widget-required'] ?? false);
4218
+ const errors = validateWidget(value, widget['widget-data-validation'], isRequired, skipRequired);
4109
4219
  if (errors.length > 0) {
4110
4220
  isValid = false;
4111
4221
  dispatch(setTouched({ widgetId, touched: true }));
@@ -4138,6 +4248,108 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
4138
4248
  return isValid;
4139
4249
  };
4140
4250
 
4251
+ const cloneValue = (value) => {
4252
+ if (value === undefined) {
4253
+ return undefined;
4254
+ }
4255
+ try {
4256
+ return structuredClone(value);
4257
+ }
4258
+ catch {
4259
+ return JSON.parse(JSON.stringify(value));
4260
+ }
4261
+ };
4262
+ const resolveNamespacedWidgetId = (widgetId, namespace) => namespace ? `${namespace}__${widgetId}` : widgetId;
4263
+ const resolveStoreDataPath = (dataPath, namespace) => {
4264
+ if (!dataPath) {
4265
+ return dataPath;
4266
+ }
4267
+ if (!namespace) {
4268
+ return dataPath;
4269
+ }
4270
+ if (typeof dataPath === 'string') {
4271
+ return `${namespace}.${dataPath}`;
4272
+ }
4273
+ return Object.fromEntries(Object.entries(dataPath).map(([key, path]) => [key, `${namespace}.${path}`]));
4274
+ };
4275
+ /**
4276
+ * Capture Redux widget values for a section at edit entry.
4277
+ * Used to restore exact pre-edit state on Cancel (schemaData may be stale or shared with Redux).
4278
+ */
4279
+ function captureSectionEditSnapshot(values, section, options) {
4280
+ const { namespace, sectionId, supportingDocuments = [] } = options ?? {};
4281
+ const dataPaths = [];
4282
+ const processedPaths = new Set();
4283
+ const widgetIds = {};
4284
+ const addPath = (path) => {
4285
+ if (!path || processedPaths.has(path)) {
4286
+ return;
4287
+ }
4288
+ processedPaths.add(path);
4289
+ dataPaths.push({
4290
+ path,
4291
+ value: cloneValue(getValueByPath(values, path)),
4292
+ });
4293
+ if (path.endsWith('.geo_code_hierarchy_json')) {
4294
+ const prefix = path.slice(0, -'.geo_code_hierarchy_json'.length);
4295
+ addPath(`${prefix}.geo_lowest_level_value_id`);
4296
+ }
4297
+ };
4298
+ collectWidgets(section.panels).forEach((widget) => {
4299
+ const widgetId = resolveNamespacedWidgetId(widget['widget-id'], namespace);
4300
+ const storeDataPath = resolveStoreDataPath(widget['widget-data-path'], namespace);
4301
+ if (Object.prototype.hasOwnProperty.call(values, widgetId)) {
4302
+ widgetIds[widgetId] = { present: true, value: cloneValue(values[widgetId]) };
4303
+ }
4304
+ else {
4305
+ widgetIds[widgetId] = { present: false };
4306
+ }
4307
+ if (typeof storeDataPath === 'string') {
4308
+ addPath(storeDataPath);
4309
+ }
4310
+ else if (storeDataPath && typeof storeDataPath === 'object') {
4311
+ Object.values(storeDataPath).forEach((path) => {
4312
+ if (typeof path === 'string') {
4313
+ addPath(path);
4314
+ }
4315
+ });
4316
+ }
4317
+ });
4318
+ supportingDocuments.forEach((doc, index) => {
4319
+ const widgetId = `supporting-doc-${sectionId ?? 'section'}-${index}`;
4320
+ const storeDataPath = namespace && doc['document-data-path']
4321
+ ? `${namespace}.${doc['document-data-path']}`
4322
+ : doc['document-data-path'];
4323
+ if (Object.prototype.hasOwnProperty.call(values, widgetId)) {
4324
+ widgetIds[widgetId] = { present: true, value: cloneValue(values[widgetId]) };
4325
+ }
4326
+ else {
4327
+ widgetIds[widgetId] = { present: false };
4328
+ }
4329
+ if (typeof storeDataPath === 'string') {
4330
+ addPath(storeDataPath);
4331
+ }
4332
+ });
4333
+ return { dataPaths, widgetIds };
4334
+ }
4335
+ /** Apply a section edit snapshot back onto the full Redux values object. */
4336
+ function applySectionEditSnapshot(currentValues, snapshot) {
4337
+ let result = currentValues;
4338
+ for (const { path, value } of snapshot.dataPaths) {
4339
+ result = setValueByPath(result, path, cloneValue(value));
4340
+ }
4341
+ for (const [widgetId, entry] of Object.entries(snapshot.widgetIds)) {
4342
+ if (entry.present) {
4343
+ result = { ...result, [widgetId]: cloneValue(entry.value) };
4344
+ }
4345
+ else {
4346
+ const { [widgetId]: _removed, ...rest } = result;
4347
+ result = rest;
4348
+ }
4349
+ }
4350
+ return result;
4351
+ }
4352
+
4141
4353
  /** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
4142
4354
  const READONLY_VALUE_ROW_ROOT_CLASSES = [
4143
4355
  'TextDisplayWidget',
@@ -4349,6 +4561,8 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4349
4561
  }, [forceExitEdit]); // eslint-disable-line react-hooks/exhaustive-deps
4350
4562
  const [isDocumentsExpanded, setIsDocumentsExpanded] = useState(true);
4351
4563
  const sectionRef = useRef(null);
4564
+ const baselineSnapshotRef = useRef(null);
4565
+ const editEntrySnapshotRef = useRef(null);
4352
4566
  const [sectionHeight, setSectionHeight] = useState(null);
4353
4567
  const [editSectionPosition, setEditSectionPosition] = useState(null);
4354
4568
  // Capture section position when entering edit mode and update on scroll
@@ -4413,6 +4627,18 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4413
4627
  panels: makePanelsEditable(sectionToRender.panels, widgetsEditable),
4414
4628
  };
4415
4629
  }, [sectionToRender, widgetsEditable]);
4630
+ const effectiveHideEditButton = hideEditButton ||
4631
+ section['section-hide-edit-button'] === true ||
4632
+ !collectWidgets(section.panels || []).some((w) => section['section-editable'] === true || w['widget-readonly'] !== true);
4633
+ const captureEditEntrySnapshot = useCallback(() => {
4634
+ const currentValues = store.getState().widget.values;
4635
+ const supportingDocuments = section['section-supporting-documents'] || [];
4636
+ editEntrySnapshotRef.current = captureSectionEditSnapshot(currentValues, section, {
4637
+ namespace,
4638
+ sectionId,
4639
+ supportingDocuments: hasSupportingDocuments ? supportingDocuments : [],
4640
+ });
4641
+ }, [store, section, namespace, sectionId, hasSupportingDocuments]);
4416
4642
  // Handle edit button click
4417
4643
  const handleEdit = () => {
4418
4644
  // Capture height BEFORE entering edit mode to preserve space
@@ -4420,6 +4646,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4420
4646
  const height = sectionRef.current.offsetHeight;
4421
4647
  setSectionHeight(height);
4422
4648
  }
4649
+ captureEditEntrySnapshot();
4423
4650
  setIsEditMode(true);
4424
4651
  onEditModeChange?.(originalSectionId, true);
4425
4652
  };
@@ -4594,8 +4821,6 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4594
4821
  }
4595
4822
  return { records, files };
4596
4823
  }, [originalSection, hasSupportingDocuments]);
4597
- // Capture baseline when entering edit mode (used for isDirty comparison)
4598
- const baselineSnapshotRef = useRef(null);
4599
4824
  // IntakeForm only: increment when baseline is updated after save - forces badge to update (refs don't trigger re-renders)
4600
4825
  const [intakeFormBaselineTrigger, setIntakeFormBaselineTrigger] = useState(0);
4601
4826
  // IntakeForm: treat as edit mode for dirty tracking when isDraft. RegistryView: use isEditMode.
@@ -4613,6 +4838,9 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4613
4838
  // Set baseline when entering edit mode; clear when leaving (baseline captured only on entry)
4614
4839
  useEffect(() => {
4615
4840
  if (effectiveEditModeForDirty) {
4841
+ if (!editEntrySnapshotRef.current) {
4842
+ captureEditEntrySnapshot();
4843
+ }
4616
4844
  const oldSchemaData = schemaData || contextSchemaData || {};
4617
4845
  if (namespace) {
4618
4846
  const namespacedSchema = getValueByPath(oldSchemaData, namespace);
@@ -4621,11 +4849,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4621
4849
  : buildSectionSnapshot(oldSchemaData);
4622
4850
  }
4623
4851
  else {
4624
- baselineSnapshotRef.current = buildSectionSnapshot(oldSchemaData);
4852
+ baselineSnapshotRef.current = buildSectionSnapshot(store.getState().widget.values, namespace);
4625
4853
  }
4626
4854
  }
4627
4855
  else {
4628
4856
  baselineSnapshotRef.current = null;
4857
+ editEntrySnapshotRef.current = null;
4629
4858
  onSectionDirtyChange?.(sectionId, false);
4630
4859
  }
4631
4860
  // eslint-disable-next-line react-hooks/exhaustive-deps -- baseline must be captured only when effectiveEditModeForDirty toggles
@@ -4651,56 +4880,103 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4651
4880
  // and handleCancel.
4652
4881
  const revertToOriginalValues = useCallback(() => {
4653
4882
  const sectionWidgets = collectWidgets(originalSection.panels);
4654
- const oldSchemaData = schemaData || contextSchemaData;
4655
4883
  const currentStoreValues = store.getState().widget.values;
4884
+ const snapshot = editEntrySnapshotRef.current;
4656
4885
  let newStoreValues = currentStoreValues;
4657
- sectionWidgets.forEach(widget => {
4658
- const originalWidgetId = widget['widget-id'];
4659
- const namespacedWidgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
4660
- const widgetId = namespacedWidgetId;
4661
- const originalDataPath = widget['widget-data-path'];
4662
- const storeDataPath = namespace && originalDataPath
4663
- ? (typeof originalDataPath === 'string'
4664
- ? `${namespace}.${originalDataPath}`
4665
- : Object.fromEntries(Object.entries(originalDataPath).map(([key, path]) => [key, `${namespace}.${path}`])))
4666
- : originalDataPath;
4667
- if (widgetId && originalDataPath) {
4668
- let oldValue;
4669
- if (typeof originalDataPath === 'object') {
4670
- oldValue = {};
4671
- Object.entries(originalDataPath).forEach(([key, path]) => {
4672
- if (typeof path === 'string') {
4673
- oldValue[key] = getValueByPath(oldSchemaData, path);
4886
+ if (snapshot) {
4887
+ newStoreValues = applySectionEditSnapshot(currentStoreValues, snapshot);
4888
+ }
4889
+ else {
4890
+ const oldSchemaData = schemaData || contextSchemaData;
4891
+ const processedGeoGroups = new Set();
4892
+ sectionWidgets.forEach((widget) => {
4893
+ const originalWidgetId = widget['widget-id'];
4894
+ const namespacedWidgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
4895
+ const widgetId = namespacedWidgetId;
4896
+ const originalDataPath = widget['widget-data-path'];
4897
+ const storeDataPath = namespace && originalDataPath
4898
+ ? (typeof originalDataPath === 'string'
4899
+ ? `${namespace}.${originalDataPath}`
4900
+ : Object.fromEntries(Object.entries(originalDataPath).map(([key, path]) => [key, `${namespace}.${path}`])))
4901
+ : originalDataPath;
4902
+ const geoConfig = widget['widget-geo-config'];
4903
+ if (widgetId && originalDataPath) {
4904
+ let oldValue;
4905
+ if (typeof originalDataPath === 'object') {
4906
+ oldValue = {};
4907
+ Object.entries(originalDataPath).forEach(([key, path]) => {
4908
+ if (typeof path === 'string') {
4909
+ oldValue[key] = getValueByPath(oldSchemaData, path);
4910
+ }
4911
+ });
4912
+ }
4913
+ else if (typeof originalDataPath === 'string') {
4914
+ oldValue = getValueByPath(oldSchemaData, originalDataPath);
4915
+ }
4916
+ if (oldValue !== undefined) {
4917
+ newStoreValues = setWidgetValue(newStoreValues, storeDataPath, widgetId, oldValue);
4918
+ if (geoConfig && typeof storeDataPath === 'string') {
4919
+ const groupId = getGeoGroupId(storeDataPath);
4920
+ const levelValue = resolveGeoWidgetLevelValue(newStoreValues, widgetId, storeDataPath, geoConfig);
4921
+ if (levelValue !== undefined && levelValue !== null && levelValue !== '') {
4922
+ newStoreValues = { ...newStoreValues, [widgetId]: levelValue };
4923
+ }
4924
+ else {
4925
+ const { [widgetId]: _removed, ...rest } = newStoreValues;
4926
+ newStoreValues = rest;
4927
+ }
4928
+ if (!processedGeoGroups.has(groupId)) {
4929
+ resetAndSeedGeoHierarchyFromValues(newStoreValues, storeDataPath, widgetId, groupId);
4930
+ processedGeoGroups.add(groupId);
4931
+ }
4932
+ if (geoConfig.parentWidgetId) {
4933
+ dispatch(setDataSource({ widgetId, data: [] }));
4934
+ }
4674
4935
  }
4675
- });
4676
- }
4677
- else if (typeof originalDataPath === 'string') {
4678
- oldValue = getValueByPath(oldSchemaData, originalDataPath);
4936
+ else {
4937
+ newStoreValues = { ...newStoreValues, [widgetId]: oldValue };
4938
+ }
4939
+ }
4679
4940
  }
4680
- if (oldValue !== undefined) {
4941
+ });
4942
+ if (hasSupportingDocuments) {
4943
+ const originalSupportingDocuments = originalSection['section-supporting-documents'] || [];
4944
+ originalSupportingDocuments.forEach((doc, index) => {
4945
+ const widgetId = `supporting-doc-${sectionId}-${index}`;
4946
+ const originalDataPath = doc['document-data-path'];
4947
+ const storeDataPath = namespace && originalDataPath
4948
+ ? `${namespace}.${originalDataPath}`
4949
+ : originalDataPath;
4950
+ const oldValue = getValueByPath(oldSchemaData, originalDataPath);
4681
4951
  newStoreValues = setWidgetValue(newStoreValues, storeDataPath, widgetId, oldValue);
4682
- // Also revert the widgetId-based entry — useBaseWidget.handleChange
4683
- // sets values[widgetId] during editing, and useBaseWidget.currentValue
4684
- // reads values[widgetId] first before falling through to the dataPath.
4685
- newStoreValues = { ...newStoreValues, [widgetId]: oldValue };
4686
- }
4952
+ });
4687
4953
  }
4688
- });
4689
- if (hasSupportingDocuments) {
4690
- const originalSupportingDocuments = originalSection['section-supporting-documents'] || [];
4691
- originalSupportingDocuments.forEach((doc, index) => {
4692
- const widgetId = `supporting-doc-${sectionId}-${index}`;
4693
- const originalDataPath = doc['document-data-path'];
4694
- const storeDataPath = namespace && originalDataPath
4695
- ? `${namespace}.${originalDataPath}`
4696
- : originalDataPath;
4697
- const oldValue = getValueByPath(oldSchemaData, originalDataPath);
4698
- newStoreValues = setWidgetValue(newStoreValues, storeDataPath, widgetId, oldValue);
4699
- });
4700
- }
4701
- if (newStoreValues !== currentStoreValues) {
4702
- dispatch(setValues(newStoreValues));
4703
4954
  }
4955
+ const processedGeoGroups = new Set();
4956
+ sectionWidgets.forEach((widget) => {
4957
+ const geoConfig = widget['widget-geo-config'];
4958
+ if (!geoConfig) {
4959
+ return;
4960
+ }
4961
+ const originalWidgetId = widget['widget-id'];
4962
+ const widgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
4963
+ const originalDataPath = widget['widget-data-path'];
4964
+ const storeDataPath = namespace && typeof originalDataPath === 'string'
4965
+ ? `${namespace}.${originalDataPath}`
4966
+ : originalDataPath;
4967
+ if (typeof storeDataPath !== 'string') {
4968
+ return;
4969
+ }
4970
+ const groupId = getGeoGroupId(storeDataPath);
4971
+ if (!processedGeoGroups.has(groupId)) {
4972
+ resetAndSeedGeoHierarchyFromValues(newStoreValues, storeDataPath, widgetId, groupId);
4973
+ processedGeoGroups.add(groupId);
4974
+ }
4975
+ if (geoConfig.parentWidgetId) {
4976
+ dispatch(setDataSource({ widgetId, data: [] }));
4977
+ }
4978
+ });
4979
+ dispatch(setValues(newStoreValues));
4704
4980
  }, [originalSection, schemaData, contextSchemaData, store, namespace, hasSupportingDocuments, sectionId, dispatch]);
4705
4981
  // Handle save button click
4706
4982
  const handleSave = async () => {
@@ -5196,7 +5472,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
5196
5472
  color: changeRequestType === 'new' ? 'var(--owt-color-bg, #FFFFFF)' : 'var(--owt-color-error, #B91C1C)',
5197
5473
  whiteSpace: 'nowrap',
5198
5474
  boxShadow: changeRequestType === 'new' ? '0 2px 4px rgba(40, 167, 69, 0.3)' : 'none',
5199
- }, 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: {
5475
+ }, 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: {
5200
5476
  marginTop: '20px',
5201
5477
  paddingBottom: '30px',
5202
5478
  display: 'flex',
@@ -5244,7 +5520,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
5244
5520
  fontSize: '14px',
5245
5521
  color: 'var(--owt-color-text, #011627)',
5246
5522
  fontWeight: 'normal',
5247
- }, 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: {
5523
+ }, 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: {
5248
5524
  fontFamily: 'Roboto, sans-serif',
5249
5525
  fontSize: '16px',
5250
5526
  color: 'var(--owt-color-text-muted, #727474)',
@@ -6050,7 +6326,7 @@ const JSONEditorPanel = ({ section, onChange, onReset, context = 'section', }) =
6050
6326
  'widget-data-format.dateConstraint': ['any', 'past-only', 'future-only'],
6051
6327
  'widget-data-format.dateTimeConstraint': ['any', 'past-only', 'future-only'],
6052
6328
  // Widget options
6053
- 'widget-data-options.action': ['show', 'hide', 'enable', 'disable'],
6329
+ 'widget-data-options.action': ['show', 'hide', 'enable', 'disable', 'require'],
6054
6330
  'widget-data-options.condition.operator': CONDITION_OPERATORS,
6055
6331
  };
6056
6332
  }, []);
@@ -7435,7 +7711,7 @@ const removeMask = (value, mask) => {
7435
7711
  };
7436
7712
 
7437
7713
  const TextInputWidget = ({ config }) => {
7438
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
7714
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
7439
7715
  const { translate, translateConfig } = useWidgetTranslation();
7440
7716
  // Track raw value separately for masking (to preserve unmasked value internally)
7441
7717
  const formatConfig = widgetConfig['widget-data-format'];
@@ -7572,7 +7848,7 @@ const TextInputWidget = ({ config }) => {
7572
7848
  const label = translateConfig(widgetConfig['widget-label']);
7573
7849
  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 }) })] }));
7574
7850
  }
7575
- 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
7851
+ 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
7576
7852
  ? 'decimal'
7577
7853
  : formatConfig?.characterType === 'numeric' || formatConfig?.characterType === 'numeric-decimal'
7578
7854
  ? 'numeric'
@@ -7595,7 +7871,7 @@ const NumberInputWidget = ({ config }) => {
7595
7871
  }
7596
7872
  return { ...config, 'widget-data-default': normalizedDefault };
7597
7873
  }, [config]);
7598
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
7874
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
7599
7875
  const { translate, translateConfig } = useWidgetTranslation();
7600
7876
  const formatConfig = widgetConfig['widget-data-format'];
7601
7877
  const validationConfig = widgetConfig['widget-data-validation'];
@@ -7726,7 +8002,7 @@ const NumberInputWidget = ({ config }) => {
7726
8002
  const display = numValue !== null ? formatNumber(numValue, formatConfig) : '';
7727
8003
  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 }) })] }));
7728
8004
  }
7729
- 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 === ''))
8005
+ 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 === ''))
7730
8006
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
7731
8007
  : '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
7732
8008
  ? 'text-red-500'
@@ -7734,7 +8010,7 @@ const NumberInputWidget = ({ config }) => {
7734
8010
  };
7735
8011
 
7736
8012
  const BooleanWidget = ({ config }) => {
7737
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8013
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
7738
8014
  const { translate, translateConfig } = useWidgetTranslation();
7739
8015
  const formatConfig = widgetConfig['widget-data-format'];
7740
8016
  const representation = formatConfig?.booleanRepresentation || 'true-false';
@@ -7803,7 +8079,7 @@ const BooleanWidget = ({ config }) => {
7803
8079
  }
7804
8080
  // Render based on control type
7805
8081
  if (controlType === 'checkbox') {
7806
- 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] }))] })] }) }));
8082
+ 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] }))] })] }) }));
7807
8083
  }
7808
8084
  if (controlType === 'radio') {
7809
8085
  const containerClass = orientation === 'horizontal'
@@ -7811,10 +8087,10 @@ const BooleanWidget = ({ config }) => {
7811
8087
  : 'flex flex-col items-start gap-2';
7812
8088
  const radioDisabled = !isEnabled || widgetConfig['widget-readonly'];
7813
8089
  const optionDisabledClass = radioDisabled ? 'opacity-50 cursor-not-allowed' : '';
7814
- 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] }))] })] }) }));
8090
+ 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] }))] })] }) }));
7815
8091
  }
7816
8092
  // Toggle/switch control type
7817
- 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
8093
+ 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
7818
8094
  ? 'bg-blue-600 text-white border-blue-600'
7819
8095
  : '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
7820
8096
  ? 'bg-blue-600 text-white border-blue-600'
@@ -7824,7 +8100,7 @@ const BooleanWidget = ({ config }) => {
7824
8100
  };
7825
8101
 
7826
8102
  const DateInputWidget = ({ config }) => {
7827
- const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
8103
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
7828
8104
  const formValues = useSelector((state) => state.widget.values);
7829
8105
  const { translateConfig } = useWidgetTranslation();
7830
8106
  const formatConfig = widgetConfig['widget-data-format'];
@@ -8025,7 +8301,7 @@ const DateInputWidget = ({ config }) => {
8025
8301
  }
8026
8302
  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 }) })] }));
8027
8303
  }
8028
- 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
8304
+ 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
8029
8305
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8030
8306
  : '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] })] })] }) }));
8031
8307
  };
@@ -8315,7 +8591,7 @@ const validateDateTimeConstraints = (date, minDateTime, maxDateTime, constraint)
8315
8591
  };
8316
8592
 
8317
8593
  const DateTimeInputWidget = ({ config }) => {
8318
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8594
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8319
8595
  const { translate, translateConfig } = useWidgetTranslation();
8320
8596
  const formatConfig = widgetConfig['widget-data-format'];
8321
8597
  const optionsConfig = widgetConfig['widget-data-options'];
@@ -8468,29 +8744,31 @@ const DateTimeInputWidget = ({ config }) => {
8468
8744
  }
8469
8745
  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 }) })] }));
8470
8746
  }
8471
- 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 === ''))
8747
+ 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 === ''))
8472
8748
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8473
8749
  : '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] }))] })] }) }));
8474
8750
  };
8475
8751
 
8476
8752
  const SelectWidget = ({ config }) => {
8477
- const { value, error, touched, isEnabled, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8753
+ const { value, geoDisplayLabel, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8478
8754
  const { translate, translateConfig } = useWidgetTranslation();
8479
8755
  // For readonly mode, render as display text showing only the selected label
8480
8756
  if (widgetConfig['widget-readonly']) {
8481
8757
  const label = translateConfig(widgetConfig['widget-label']);
8482
8758
  // Find the selected option's label
8483
8759
  const selectedOption = dataSourceOptions.find((option) => option.value === value);
8484
- const displayValue = selectedOption ? selectedOption.label : (value || '-');
8760
+ const displayValue = selectedOption
8761
+ ? translateConfig(selectedOption.label)
8762
+ : (geoDisplayLabel || (value != null && value !== '' ? translateConfig(String(value)) : '-'));
8485
8763
  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 }) })] }));
8486
8764
  }
8487
- 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 === '' ? 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 === ''))
8765
+ 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 === ''))
8488
8766
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8489
- : '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] }))] })] }) }));
8767
+ : '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] }))] })] }) }));
8490
8768
  };
8491
8769
 
8492
8770
  const RadioWidget = ({ config }) => {
8493
- const { value, error, touched, isEnabled, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8771
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8494
8772
  const { translate, translateConfig } = useWidgetTranslation();
8495
8773
  const formatConfig = widgetConfig['widget-data-format'];
8496
8774
  const layout = formatConfig?.layout || widgetConfig['widget-orientation'] || 'vertical';
@@ -8553,14 +8831,16 @@ const RadioWidget = ({ config }) => {
8553
8831
  if (widgetConfig['widget-readonly']) {
8554
8832
  const label = translateConfig(widgetConfig['widget-label']);
8555
8833
  const selectedOption = processedOptions.find(opt => opt.value === currentValue);
8556
- const displayValue = selectedOption ? selectedOption.label : (allowUnset && currentValue === null ? '-' : '');
8834
+ const displayValue = selectedOption
8835
+ ? translateConfig(selectedOption.label)
8836
+ : (allowUnset && currentValue === null ? '-' : '');
8557
8837
  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 }) })] }));
8558
8838
  }
8559
- 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] }))] })] }) }));
8839
+ 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] }))] })] }) }));
8560
8840
  };
8561
8841
 
8562
8842
  const CheckboxWidget = ({ config }) => {
8563
- const { value, error, touched, isEnabled, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8843
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
8564
8844
  const { translate, translateConfig } = useWidgetTranslation();
8565
8845
  const hasDataSource = !!widgetConfig['widget-data-source'];
8566
8846
  const formatConfig = widgetConfig['widget-data-format'];
@@ -8575,7 +8855,7 @@ const CheckboxWidget = ({ config }) => {
8575
8855
  const displayValue = isChecked ? 'Yes' : 'No';
8576
8856
  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 }) })] }));
8577
8857
  }
8578
- 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] }))] })] }) }));
8858
+ 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] }))] })] }) }));
8579
8859
  }
8580
8860
  // Multiple checkboxes (with data source) - for array values
8581
8861
  // Process and sort options if needed
@@ -8645,7 +8925,7 @@ const CheckboxWidget = ({ config }) => {
8645
8925
  : '-';
8646
8926
  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 }) })] }));
8647
8927
  }
8648
- 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] }))] })] }) }));
8928
+ 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] }))] })] }) }));
8649
8929
  };
8650
8930
 
8651
8931
  const SimpleTableWidget = ({ config }) => {
@@ -8696,7 +8976,7 @@ const SimpleTableWidget = ({ config }) => {
8696
8976
  };
8697
8977
 
8698
8978
  const ArrayWidget = ({ config }) => {
8699
- const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
8979
+ const { value, error, touched, isEnabled, isRequired, onChange, config: widgetConfig, } = useBaseWidget({ config });
8700
8980
  const { translate, translateConfig } = useWidgetTranslation();
8701
8981
  const items = Array.isArray(value) ? value : [];
8702
8982
  const itemConfig = widgetConfig['widget-item'];
@@ -8720,7 +9000,7 @@ const ArrayWidget = ({ config }) => {
8720
9000
  newItems[index] = newValue;
8721
9001
  onChange(newItems);
8722
9002
  };
8723
- 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) => {
9003
+ 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) => {
8724
9004
  ({
8725
9005
  ...itemConfig,
8726
9006
  'widget-id': `${widgetConfig['widget-id']}-item-${index}`,
@@ -8731,7 +9011,7 @@ const ArrayWidget = ({ config }) => {
8731
9011
  };
8732
9012
 
8733
9013
  const IterableAccordionWidget = ({ config }) => {
8734
- const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
9014
+ const { value, error, touched, isEnabled, isRequired, onChange, config: widgetConfig, } = useBaseWidget({ config });
8735
9015
  const { translate, translateConfig } = useWidgetTranslation();
8736
9016
  const items = Array.isArray(value) ? value : [];
8737
9017
  const itemConfig = widgetConfig['widget-item'];
@@ -8780,7 +9060,7 @@ const IterableAccordionWidget = ({ config }) => {
8780
9060
  newItems[index] = newValue;
8781
9061
  onChange(newItems);
8782
9062
  };
8783
- 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) => {
9063
+ 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) => {
8784
9064
  const isCollapsed = collapsedItems[index] ?? defaultCollapsed;
8785
9065
  const parentPath = widgetConfig['widget-data-path'];
8786
9066
  const childPath = itemConfig['widget-data-path'];
@@ -8819,7 +9099,7 @@ const IterableAccordionWidget = ({ config }) => {
8819
9099
  };
8820
9100
 
8821
9101
  const PhoneInputWidget = ({ config }) => {
8822
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
9102
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8823
9103
  const { translate, translateConfig } = useWidgetTranslation();
8824
9104
  // Use formatted value if available, otherwise raw value
8825
9105
  const displayValue = formattedValue !== undefined && formattedValue !== value
@@ -8830,13 +9110,13 @@ const PhoneInputWidget = ({ config }) => {
8830
9110
  const label = translateConfig(widgetConfig['widget-label']);
8831
9111
  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 || '-' }) })] }));
8832
9112
  }
8833
- 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 === ''))
9113
+ 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 === ''))
8834
9114
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8835
9115
  : '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] }))] })] }) }));
8836
9116
  };
8837
9117
 
8838
9118
  const CurrencyInputWidget = ({ config }) => {
8839
- const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
9119
+ const { value, formattedValue, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
8840
9120
  const { translate, translateConfig } = useWidgetTranslation();
8841
9121
  // For input, use raw numeric value; formatted value is for display only
8842
9122
  const numericValue = typeof value === 'number' ? value : (value ? parseFloat(String(value)) : '');
@@ -8858,7 +9138,7 @@ const CurrencyInputWidget = ({ config }) => {
8858
9138
  const display = formattedValue || (value !== null && value !== undefined ? String(value) : '-');
8859
9139
  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 }) })] }));
8860
9140
  }
8861
- 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 === ''))
9141
+ 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 === ''))
8862
9142
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
8863
9143
  : '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] }))] })] }) }));
8864
9144
  };
@@ -9701,6 +9981,7 @@ const TableWidget = ({ config }) => {
9701
9981
  }, 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] }))] })] }));
9702
9982
  };
9703
9983
 
9984
+ const isUnsetRowValue = (value) => value === null || value === undefined || value === '';
9704
9985
  // Display select value label in view mode
9705
9986
  const SelectDisplayValue = ({ config, value }) => {
9706
9987
  const { dataSourceOptions, loading } = useBaseWidget({ config });
@@ -9733,7 +10014,6 @@ const DialogTableWidget = ({ config }) => {
9733
10014
  const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
9734
10015
  const { translate, translateConfig } = useWidgetTranslation();
9735
10016
  const dispatch = useDispatch();
9736
- const storeValues = useSelector((state) => state.widget?.values ?? {});
9737
10017
  const rows = Array.isArray(value) ? value : [];
9738
10018
  const columns = widgetConfig['widget-data-columns'] || [];
9739
10019
  const operations = widgetConfig['widget-data-operations'] || {};
@@ -9765,7 +10045,12 @@ const DialogTableWidget = ({ config }) => {
9765
10045
  const emptyRow = {};
9766
10046
  columns.forEach((col) => {
9767
10047
  const key = col['column-key'];
9768
- emptyRow[key] = col['widget-data-default'] ?? '';
10048
+ if (col['widget-data-default'] !== undefined) {
10049
+ emptyRow[key] = col['widget-data-default'];
10050
+ }
10051
+ else if (col.widget === 'checkbox') {
10052
+ emptyRow[key] = false;
10053
+ }
9769
10054
  });
9770
10055
  return emptyRow;
9771
10056
  }, [columns]);
@@ -9818,17 +10103,48 @@ const DialogTableWidget = ({ config }) => {
9818
10103
  const updateField = useCallback((columnKey, newValue) => {
9819
10104
  setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
9820
10105
  }, []);
9821
- const collectMergedRowPayload = useCallback(() => {
9822
- const merged = { ...formData };
10106
+ const membersWidgetId = widgetConfig['widget-id'];
10107
+ const dialogStoreValues = useSelector((state) => {
10108
+ if (dialogSessionId <= 0) {
10109
+ return {};
10110
+ }
10111
+ const values = state.widget?.values ?? {};
10112
+ const row = {};
10113
+ columns.forEach((col) => {
10114
+ const k = col['column-key'];
10115
+ const wid = `${membersWidgetId}-dlg-${dialogSessionId}-${k}`;
10116
+ if (values[wid] !== undefined) {
10117
+ row[k] = values[wid];
10118
+ }
10119
+ });
10120
+ return row;
10121
+ }, (a, b) => JSON.stringify(a) === JSON.stringify(b));
10122
+ const buildDialogRowValues = useCallback((storeSlice) => {
10123
+ const row = { ...formData };
9823
10124
  columns.forEach((col) => {
9824
10125
  const k = col['column-key'];
9825
- const wid = dialogFieldWidgetId(k);
9826
- const fromStore = storeValues[wid];
9827
- if (fromStore !== undefined)
9828
- merged[k] = fromStore;
10126
+ if (storeSlice[k] !== undefined) {
10127
+ row[k] = storeSlice[k];
10128
+ }
9829
10129
  });
9830
- return merged;
9831
- }, [formData, columns, storeValues, dialogFieldWidgetId]);
10130
+ return row;
10131
+ }, [formData, columns]);
10132
+ const dialogRowValues = useMemo(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
10133
+ const collectMergedRowPayload = useCallback(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
10134
+ const finalizeDialogRowPayload = useCallback((raw) => {
10135
+ const result = {};
10136
+ columns.forEach((col) => {
10137
+ const key = col['column-key'];
10138
+ if (!shouldShowWidget(col['widget-data-options'], raw)) {
10139
+ return;
10140
+ }
10141
+ const val = raw[key];
10142
+ if (!isUnsetRowValue(val)) {
10143
+ result[key] = val;
10144
+ }
10145
+ });
10146
+ return result;
10147
+ }, [columns]);
9832
10148
  const saveDialog = useCallback(() => {
9833
10149
  const payload = collectMergedRowPayload();
9834
10150
  let hasErrors = false;
@@ -9838,8 +10154,11 @@ const DialogTableWidget = ({ config }) => {
9838
10154
  const isColReadonly = isReadonly || col['widget-readonly'] === true;
9839
10155
  if (isColReadonly)
9840
10156
  return;
10157
+ if (!shouldShowWidget(col['widget-data-options'], payload))
10158
+ return;
9841
10159
  const cellValue = payload[key];
9842
- const validationErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
10160
+ const isRequired = shouldRequireWidget(col['widget-data-options'], payload, col['widget-required']);
10161
+ const validationErrors = validateWidget(cellValue, col['widget-data-validation'], isRequired);
9843
10162
  if (validationErrors && validationErrors.length > 0) {
9844
10163
  hasErrors = true;
9845
10164
  dispatch(setError({ widgetId: cellWidgetId, errors: validationErrors }));
@@ -9852,8 +10171,9 @@ const DialogTableWidget = ({ config }) => {
9852
10171
  if (hasErrors) {
9853
10172
  return;
9854
10173
  }
10174
+ const cleaned = finalizeDialogRowPayload(payload);
9855
10175
  if (dialogMode === 'add') {
9856
- const savedRow = { ...payload, edit_action: 'ADD' };
10176
+ const savedRow = { ...cleaned, edit_action: 'ADD' };
9857
10177
  onChange([...rows, savedRow]);
9858
10178
  closeDialog();
9859
10179
  return;
@@ -9863,11 +10183,18 @@ const DialogTableWidget = ({ config }) => {
9863
10183
  const currentRow = newRows[activeRowIndex] || {};
9864
10184
  const wasDeleted = currentRow.edit_action === 'DELETE';
9865
10185
  const editAction = wasDeleted ? 'UPDATE' : (currentRow.edit_action ?? 'UPDATE');
9866
- newRows[activeRowIndex] = { ...currentRow, ...payload, edit_action: editAction };
10186
+ const merged = { ...currentRow, ...cleaned, edit_action: editAction };
10187
+ columns.forEach((col) => {
10188
+ const key = col['column-key'];
10189
+ if (!(key in cleaned)) {
10190
+ delete merged[key];
10191
+ }
10192
+ });
10193
+ newRows[activeRowIndex] = merged;
9867
10194
  onChange(newRows);
9868
10195
  closeDialog();
9869
10196
  }
9870
- }, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
10197
+ }, [collectMergedRowPayload, finalizeDialogRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
9871
10198
  const deleteRow = useCallback((rowIndex) => {
9872
10199
  const newRows = rows.filter((_, i) => i !== rowIndex);
9873
10200
  onChange(newRows);
@@ -9954,9 +10281,12 @@ const DialogTableWidget = ({ config }) => {
9954
10281
  lineHeight: 1,
9955
10282
  }, "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) => {
9956
10283
  const key = col['column-key'];
10284
+ if (!shouldShowWidget(col['widget-data-options'], dialogRowValues)) {
10285
+ return null;
10286
+ }
9957
10287
  const widgetType = col.widget || 'text';
9958
10288
  const cellWidgetId = dialogFieldWidgetId(key);
9959
- const initialValue = formData[key] ?? col['widget-data-default'] ?? '';
10289
+ const initialValue = formData[key] ?? col['widget-data-default'];
9960
10290
  const fieldConfig = {
9961
10291
  ...col,
9962
10292
  widget: widgetType,
@@ -9966,6 +10296,8 @@ const DialogTableWidget = ({ config }) => {
9966
10296
  'widget-readonly': isReadonly || col['widget-readonly'] === true,
9967
10297
  'widget-data-path': undefined,
9968
10298
  'widget-data-default': initialValue,
10299
+ 'widget-data-options': undefined,
10300
+ 'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
9969
10301
  };
9970
10302
  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}`));
9971
10303
  }) }, `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: {
@@ -10163,7 +10495,7 @@ const ProfileWidget = ({ config }) => {
10163
10495
  const TextAreaWidget = ({ config }) => {
10164
10496
  // Check readonly early from original config
10165
10497
  const isReadonly = config['widget-readonly'] || false;
10166
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
10498
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
10167
10499
  const { translate, translateConfig } = useWidgetTranslation();
10168
10500
  const formatConfig = widgetConfig['widget-data-format'] || {};
10169
10501
  const validationConfig = widgetConfig['widget-data-validation'] || {};
@@ -10211,7 +10543,6 @@ const TextAreaWidget = ({ config }) => {
10211
10543
  ? translateConfig(widgetConfig['widget-label'])
10212
10544
  : '';
10213
10545
  // Check if required
10214
- const isRequired = widgetConfig['widget-required'] || false;
10215
10546
  // Error display
10216
10547
  const hasError = touched && error && error.length > 0;
10217
10548
  const errorMessage = hasError ? error[0] : '';
@@ -10229,7 +10560,7 @@ const TextAreaWidget = ({ config }) => {
10229
10560
  border: 'none',
10230
10561
  }, children: displayValue }) })] }));
10231
10562
  }
10232
- 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
10563
+ 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
10233
10564
  ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
10234
10565
  : 'border-gray-300'} ${!isEnabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: {
10235
10566
  borderRadius: '10px',
@@ -11707,7 +12038,7 @@ const ResultsTable = ({ rows, selectedRowKey, onRowClick, onRowDoubleClick, }) =
11707
12038
  }) })] }) }));
11708
12039
  };
11709
12040
  const RegisterLookupWidget = ({ config }) => {
11710
- const { value, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
12041
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config });
11711
12042
  const { translate, translateConfig } = useWidgetTranslation();
11712
12043
  const { dataSourceRequestHandler } = useWidgetContext();
11713
12044
  const dataSource = widgetConfig['widget-data-source'];
@@ -11870,7 +12201,7 @@ const RegisterLookupWidget = ({ config }) => {
11870
12201
  onChange(null);
11871
12202
  setAppliedRecord(null);
11872
12203
  setPendingRow(null);
11873
- }, 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: "truncate", children: actionLabel }), widgetConfig['widget-required'] && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", 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: {
12204
+ }, 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: {
11874
12205
  position: 'fixed',
11875
12206
  top: modalPos.y,
11876
12207
  left: modalPos.x,
@@ -11899,6 +12230,288 @@ const RegisterLookupWidget = ({ config }) => {
11899
12230
  : 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 })] })] })] }))] }));
11900
12231
  };
11901
12232
 
12233
+ const MultiSelectWidget = ({ config }) => {
12234
+ const { value, error, touched, isEnabled, isRequired, onChange, onBlur, dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
12235
+ const { translate, translateConfig } = useWidgetTranslation();
12236
+ const [isOpen, setIsOpen] = useState(false);
12237
+ const [isListPopupOpen, setIsListPopupOpen] = useState(false);
12238
+ const [searchQuery, setSearchQuery] = useState('');
12239
+ const [dropdownPosition, setDropdownPosition] = useState(null);
12240
+ const [listPopupPosition, setListPopupPosition] = useState(null);
12241
+ const [mounted, setMounted] = useState(false);
12242
+ const containerRef = useRef(null);
12243
+ const triggerRef = useRef(null);
12244
+ const dropdownRef = useRef(null);
12245
+ const listPopupRef = useRef(null);
12246
+ const moreButtonRef = useRef(null);
12247
+ const searchInputRef = useRef(null);
12248
+ const formatConfig = widgetConfig['widget-data-format'];
12249
+ const sortOptions = formatConfig?.sortOptions ?? false;
12250
+ useEffect(() => {
12251
+ setMounted(true);
12252
+ }, []);
12253
+ const updateDropdownPosition = useCallback(() => {
12254
+ const trigger = triggerRef.current;
12255
+ if (!trigger)
12256
+ return;
12257
+ const rect = trigger.getBoundingClientRect();
12258
+ const gap = 4;
12259
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
12260
+ const spaceAbove = rect.top - gap;
12261
+ const openDown = spaceBelow >= 160 || spaceBelow >= spaceAbove;
12262
+ const availableSpace = openDown ? spaceBelow : spaceAbove;
12263
+ const maxHeight = Math.min(320, Math.max(160, availableSpace - 8));
12264
+ setDropdownPosition(openDown
12265
+ ? {
12266
+ top: rect.bottom + gap,
12267
+ left: rect.left,
12268
+ width: rect.width,
12269
+ maxHeight,
12270
+ placement: 'bottom',
12271
+ }
12272
+ : {
12273
+ bottom: window.innerHeight - rect.top + gap,
12274
+ left: rect.left,
12275
+ width: rect.width,
12276
+ maxHeight,
12277
+ placement: 'top',
12278
+ });
12279
+ }, []);
12280
+ const updateListPopupPosition = useCallback(() => {
12281
+ const anchor = moreButtonRef.current;
12282
+ if (!anchor)
12283
+ return;
12284
+ const rect = anchor.getBoundingClientRect();
12285
+ const gap = 4;
12286
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
12287
+ const spaceAbove = rect.top - gap;
12288
+ const openDown = spaceBelow >= 120 || spaceBelow >= spaceAbove;
12289
+ const availableSpace = openDown ? spaceBelow : spaceAbove;
12290
+ const maxHeight = Math.min(280, Math.max(120, availableSpace - 8));
12291
+ setListPopupPosition(openDown
12292
+ ? {
12293
+ top: rect.bottom + gap,
12294
+ left: rect.left,
12295
+ width: Math.max(rect.width, 220),
12296
+ maxHeight,
12297
+ placement: 'bottom',
12298
+ }
12299
+ : {
12300
+ bottom: window.innerHeight - rect.top + gap,
12301
+ left: rect.left,
12302
+ width: Math.max(rect.width, 220),
12303
+ maxHeight,
12304
+ placement: 'top',
12305
+ });
12306
+ }, []);
12307
+ useEffect(() => {
12308
+ if (!isOpen) {
12309
+ setDropdownPosition(null);
12310
+ setSearchQuery('');
12311
+ return;
12312
+ }
12313
+ updateDropdownPosition();
12314
+ const handleResize = () => updateDropdownPosition();
12315
+ window.addEventListener('resize', handleResize);
12316
+ return () => {
12317
+ window.removeEventListener('resize', handleResize);
12318
+ };
12319
+ }, [isOpen, updateDropdownPosition]);
12320
+ useEffect(() => {
12321
+ if (!isListPopupOpen) {
12322
+ setListPopupPosition(null);
12323
+ return;
12324
+ }
12325
+ updateListPopupPosition();
12326
+ const handleResize = () => updateListPopupPosition();
12327
+ window.addEventListener('resize', handleResize);
12328
+ return () => {
12329
+ window.removeEventListener('resize', handleResize);
12330
+ };
12331
+ }, [isListPopupOpen, updateListPopupPosition]);
12332
+ useEffect(() => {
12333
+ if (!isOpen && !isListPopupOpen)
12334
+ return;
12335
+ const handleScroll = (event) => {
12336
+ const target = event.target;
12337
+ if (dropdownRef.current?.contains(target))
12338
+ return;
12339
+ if (listPopupRef.current?.contains(target))
12340
+ return;
12341
+ if (isOpen)
12342
+ setIsOpen(false);
12343
+ if (isListPopupOpen)
12344
+ setIsListPopupOpen(false);
12345
+ };
12346
+ window.addEventListener('scroll', handleScroll, true);
12347
+ return () => window.removeEventListener('scroll', handleScroll, true);
12348
+ }, [isOpen, isListPopupOpen]);
12349
+ useEffect(() => {
12350
+ if (!isOpen && !isListPopupOpen)
12351
+ return;
12352
+ const handleClickOutside = (event) => {
12353
+ const target = event.target;
12354
+ if (isOpen) {
12355
+ if (containerRef.current?.contains(target))
12356
+ return;
12357
+ if (dropdownRef.current?.contains(target))
12358
+ return;
12359
+ setIsOpen(false);
12360
+ }
12361
+ if (isListPopupOpen) {
12362
+ if (listPopupRef.current?.contains(target))
12363
+ return;
12364
+ if (moreButtonRef.current?.contains(target))
12365
+ return;
12366
+ setIsListPopupOpen(false);
12367
+ }
12368
+ };
12369
+ document.addEventListener('mousedown', handleClickOutside);
12370
+ return () => document.removeEventListener('mousedown', handleClickOutside);
12371
+ }, [isOpen, isListPopupOpen]);
12372
+ useEffect(() => {
12373
+ if (isOpen && searchInputRef.current) {
12374
+ searchInputRef.current.focus();
12375
+ }
12376
+ }, [isOpen]);
12377
+ const processedOptions = useMemo(() => {
12378
+ let options = dataSourceOptions.map((opt) => {
12379
+ const rawLabel = String(opt.label ?? opt.value ?? '');
12380
+ return {
12381
+ value: opt.value,
12382
+ label: translateConfig(rawLabel),
12383
+ rawLabel,
12384
+ };
12385
+ });
12386
+ if (sortOptions) {
12387
+ options.sort((a, b) => a.label.localeCompare(b.label));
12388
+ }
12389
+ return options;
12390
+ }, [dataSourceOptions, sortOptions, translateConfig]);
12391
+ const filteredOptions = useMemo(() => {
12392
+ if (!searchQuery.trim())
12393
+ return processedOptions;
12394
+ const q = searchQuery.trim().toLowerCase();
12395
+ return processedOptions.filter((opt) => opt.label.toLowerCase().includes(q) ||
12396
+ opt.rawLabel.toLowerCase().includes(q));
12397
+ }, [processedOptions, searchQuery]);
12398
+ const selectedValues = useMemo(() => {
12399
+ if (value === null || value === undefined)
12400
+ return [];
12401
+ if (Array.isArray(value))
12402
+ return value;
12403
+ return [value];
12404
+ }, [value]);
12405
+ const allFilteredSelected = useMemo(() => {
12406
+ if (filteredOptions.length === 0)
12407
+ return false;
12408
+ return filteredOptions.every((opt) => selectedValues.includes(opt.value));
12409
+ }, [filteredOptions, selectedValues]);
12410
+ const handleToggle = useCallback((optionValue, checked) => {
12411
+ if (checked) {
12412
+ onChange([...selectedValues, optionValue]);
12413
+ }
12414
+ else {
12415
+ onChange(selectedValues.filter((v) => v !== optionValue));
12416
+ }
12417
+ }, [selectedValues, onChange]);
12418
+ const handleSelectAll = useCallback(() => {
12419
+ const filteredVals = filteredOptions.map((o) => o.value);
12420
+ const merged = Array.from(new Set([...selectedValues, ...filteredVals]));
12421
+ onChange(merged);
12422
+ }, [filteredOptions, selectedValues, onChange]);
12423
+ const handleClearAll = useCallback(() => {
12424
+ onChange([]);
12425
+ }, [onChange]);
12426
+ const selectedLabels = useMemo(() => {
12427
+ return selectedValues.map((val) => {
12428
+ const opt = processedOptions.find((o) => o.value === val);
12429
+ return opt ? opt.label : translateConfig(String(val));
12430
+ });
12431
+ }, [selectedValues, processedOptions, translateConfig]);
12432
+ const fullSelectionText = selectedLabels.join(', ');
12433
+ const visibleLabels = selectedLabels.slice(0, 5);
12434
+ const overflowCount = Math.max(0, selectedLabels.length - 10);
12435
+ const disabled = !isEnabled || loading || widgetConfig['widget-readonly'];
12436
+ const renderSelectedLabels = (options) => {
12437
+ if (selectedLabels.length === 0)
12438
+ return null;
12439
+ const readonly = options?.readonly ?? false;
12440
+ 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', {
12441
+ label,
12442
+ defaultValue: `Remove ${label}`,
12443
+ }), 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', {
12444
+ count: overflowCount,
12445
+ defaultValue: `+${overflowCount} more`,
12446
+ }) }))] }));
12447
+ };
12448
+ const listPopupPanel = isListPopupOpen && listPopupPosition && mounted ? (jsxRuntimeExports.jsxs("div", { ref: listPopupRef, className: "fixed z-[201] bg-white border border-gray-300 shadow-lg", style: {
12449
+ ...(listPopupPosition.placement === 'bottom'
12450
+ ? { top: listPopupPosition.top }
12451
+ : { bottom: listPopupPosition.bottom }),
12452
+ left: listPopupPosition.left,
12453
+ width: listPopupPosition.width,
12454
+ maxWidth: '320px',
12455
+ maxHeight: listPopupPosition.maxHeight,
12456
+ borderRadius: '10px',
12457
+ display: 'flex',
12458
+ flexDirection: 'column',
12459
+ }, 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', {
12460
+ count: selectedLabels.length,
12461
+ defaultValue: `All selected (${selectedLabels.length})`,
12462
+ }) }), 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;
12463
+ if (widgetConfig['widget-readonly']) {
12464
+ const fieldLabel = widgetConfig['widget-label'];
12465
+ 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'
12466
+ ? createPortal(listPopupPanel, document.body)
12467
+ : null] })] }));
12468
+ }
12469
+ const optionsMaxHeight = dropdownPosition
12470
+ ? Math.min(280, dropdownPosition.maxHeight - 100)
12471
+ : 280;
12472
+ const dropdownPanel = isOpen && dropdownPosition && mounted ? (jsxRuntimeExports.jsxs("div", { ref: dropdownRef, className: "fixed z-[200] bg-white border border-gray-300 shadow-lg", style: {
12473
+ ...(dropdownPosition.placement === 'bottom'
12474
+ ? { top: dropdownPosition.top }
12475
+ : { bottom: dropdownPosition.bottom }),
12476
+ left: dropdownPosition.left,
12477
+ width: dropdownPosition.width,
12478
+ maxWidth: '280px',
12479
+ maxHeight: dropdownPosition.maxHeight,
12480
+ borderRadius: '10px',
12481
+ display: 'flex',
12482
+ flexDirection: 'column',
12483
+ }, 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 ? () => {
12484
+ const filteredVals = new Set(filteredOptions.map((o) => o.value));
12485
+ onChange(selectedValues.filter((v) => !filteredVals.has(v)));
12486
+ } : handleSelectAll, className: "text-xs font-medium text-blue-600 hover:text-blue-800 focus:outline-none", children: allFilteredSelected
12487
+ ? translate('common.deselectAll', { defaultValue: 'Deselect All' })
12488
+ : 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) => {
12489
+ const isChecked = selectedValues.includes(option.value);
12490
+ 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));
12491
+ })) })] })) : null;
12492
+ 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: () => {
12493
+ if (!disabled)
12494
+ setIsOpen((prev) => !prev);
12495
+ }, onBlur: () => {
12496
+ if (!isOpen)
12497
+ onBlur();
12498
+ }, 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) ||
12499
+ (widgetConfig['widget-required'] && selectedValues.length === 0)
12500
+ ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
12501
+ : '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
12502
+ ? fullSelectionText
12503
+ : 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
12504
+ ? translate('common.select', { defaultValue: 'Select...' })
12505
+ : translate('common.selectedCount', {
12506
+ count: selectedLabels.length,
12507
+ defaultValue: `${selectedLabels.length} selected`,
12508
+ }) }), 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'
12509
+ ? createPortal(dropdownPanel, document.body)
12510
+ : null, selectedLabels.length > 0 && renderSelectedLabels(), mounted && listPopupPanel && typeof document !== 'undefined'
12511
+ ? createPortal(listPopupPanel, document.body)
12512
+ : 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') }))] })] }) }));
12513
+ };
12514
+
11902
12515
  /**
11903
12516
  * Register all default/generic widgets
11904
12517
  * This is called automatically when the package is imported
@@ -11948,6 +12561,8 @@ const registerDefaultWidgets = () => {
11948
12561
  widgetRegistry.register({ widget: 'id-authentication', component: IdAuthenticationWidget });
11949
12562
  // Register lookup widget — searchable popup to select a record from any register
11950
12563
  widgetRegistry.register({ widget: 'register-lookup', component: RegisterLookupWidget });
12564
+ // Multi-select widget — searchable dropdown with checkbox-style options, select all, and clear all
12565
+ widgetRegistry.register({ widget: 'multi-select', component: MultiSelectWidget });
11951
12566
  };
11952
12567
  // Auto-register on import
11953
12568
  registerDefaultWidgets();
@@ -12011,6 +12626,14 @@ var enTranslations = {
12011
12626
  "common.sectionModified": "Modified and not saved",
12012
12627
  "common.supportedDocuments": "Supported Documents",
12013
12628
  "common.searchPlaceholder": "Search...",
12629
+ "common.selectAll": "Select All",
12630
+ "common.deselectAll": "Deselect All",
12631
+ "common.clearAll": "Clear All",
12632
+ "common.noOptionsFound": "No options found",
12633
+ "common.allSelected": "All selected ({{count}})",
12634
+ "common.moreSelected": "+{{count}} more",
12635
+ "common.selectedCount": "{{count}} selected",
12636
+ "common.removeItem": "Remove {{label}}",
12014
12637
  "common.selectAction": "Select {{label}}",
12015
12638
  "common.selectTitle": "Select {{label}}",
12016
12639
  "common.change": "Change",
@@ -12263,13 +12886,10 @@ const translateWidgetConfig = (widgetConfig, translate) => {
12263
12886
  ...dataSource,
12264
12887
  options: dataSource.options.map((option) => {
12265
12888
  if (option.label && typeof option.label === 'string') {
12266
- const optionLabel = option.label;
12267
- if (isTranslationKey(optionLabel)) {
12268
- return {
12269
- ...option,
12270
- label: translate(optionLabel, { defaultValue: optionLabel }),
12271
- };
12272
- }
12889
+ return {
12890
+ ...option,
12891
+ label: translate(option.label, { defaultValue: option.label }),
12892
+ };
12273
12893
  }
12274
12894
  return option;
12275
12895
  }),
@@ -12322,5 +12942,5 @@ const translateUISchema = (schema, translate) => {
12322
12942
  };
12323
12943
  };
12324
12944
 
12325
- export { ArrayWidget, BooleanWidget, CheckboxWidget, CurrencyInputWidget, DateInputWidget, DateTimeInputWidget, DialogTableWidget, DisplayWidget, FileInputWidget, GEO_LEVEL_CLEARED, HeaderSectionWidget, IdAuthenticationWidget, IterableAccordionWidget, JSONEditorPanel, 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, 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 };
12945
+ 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, createWidgetStore, createZodSchema, defaultTheme, evaluateCondition, evaluateWidgetConditions, filterByCharacterType, formatCurrency, formatDate, formatNumber, formatPhone, formatValue, geoHierarchyBuilder, getApiDataSource, getFormattedNumberLength, getGeoDescendantWidgetIds, getGeoGroupId, getSchemaDataSource, getStaticDataSource, getValueByPath, getWidgetValue, hasVisibilityRules, initI18n, isAllowedKey, isUpstreamGeoAncestor, normalizeNumericDefault, normalizeOptionRules, parseDataPath, parseNumber, registerDefaultWidgets, 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, unregisterGeoWidgetParent, useBaseWidget, useGeoWidgetCascade, useWidgetCascade, useWidgetContext, useWidgetEventBus, useWidgetTheme, useWidgetTranslation, validateNumericValue, validateWidget, widgetRegistry };
12326
12946
  //# sourceMappingURL=index.esm.js.map