@openg2p/registry-widgets 1.1.2-dev.8 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2244,12 +2244,145 @@ const geoHierarchyBuilder = new GeoHierarchyBuilder();
2244
2244
  /** Sentinel written to Redux when a geo level is cleared by cascade (distinct from "never set"). */
2245
2245
  const GEO_LEVEL_CLEARED = null;
2246
2246
  const geoWidgetParentRegistry = new Map();
2247
+ const geoWidgetConfigRegistry = new Map();
2247
2248
  function registerGeoWidgetParent(widgetId, parentWidgetId) {
2248
2249
  geoWidgetParentRegistry.set(widgetId, parentWidgetId || null);
2249
2250
  }
2250
2251
  function unregisterGeoWidgetParent(widgetId) {
2251
2252
  geoWidgetParentRegistry.delete(widgetId);
2252
2253
  }
2254
+ function registerGeoWidget(widgetId, geoConfig, dataPath) {
2255
+ if (typeof dataPath !== 'string') {
2256
+ return;
2257
+ }
2258
+ const parentWidgetId = geoConfig.parentWidgetId?.trim() ? geoConfig.parentWidgetId : null;
2259
+ registerGeoWidgetParent(widgetId, parentWidgetId);
2260
+ geoWidgetConfigRegistry.set(widgetId, {
2261
+ widgetId,
2262
+ parentWidgetId,
2263
+ level: geoConfig.level,
2264
+ geoConfig,
2265
+ dataPath,
2266
+ groupId: getGeoGroupId(dataPath),
2267
+ });
2268
+ }
2269
+ function unregisterGeoWidget(widgetId) {
2270
+ unregisterGeoWidgetParent(widgetId);
2271
+ geoWidgetConfigRegistry.delete(widgetId);
2272
+ }
2273
+ function orderGeoWidgetRegistrations(registrations) {
2274
+ if (registrations.length <= 1) {
2275
+ return registrations;
2276
+ }
2277
+ const roots = registrations.filter((entry) => !entry.parentWidgetId);
2278
+ if (roots.length === 0) {
2279
+ return registrations;
2280
+ }
2281
+ const ordered = [];
2282
+ let current = roots[0];
2283
+ const visited = new Set();
2284
+ while (current && !visited.has(current.widgetId)) {
2285
+ visited.add(current.widgetId);
2286
+ ordered.push(current);
2287
+ current = registrations.find((entry) => entry.parentWidgetId === current.widgetId);
2288
+ }
2289
+ return ordered.length > 0 ? ordered : registrations;
2290
+ }
2291
+ function resolveLevelValueId(rawValue) {
2292
+ if (rawValue === null || rawValue === undefined || rawValue === '') {
2293
+ return null;
2294
+ }
2295
+ if (typeof rawValue === 'string' || typeof rawValue === 'number') {
2296
+ return String(rawValue);
2297
+ }
2298
+ if (typeof rawValue === 'object') {
2299
+ const id = rawValue.level_value_id || rawValue.id || rawValue.value;
2300
+ return id != null && id !== '' ? String(id) : null;
2301
+ }
2302
+ return null;
2303
+ }
2304
+ function resolveStoredMnemonic(values, registration, valueId) {
2305
+ const stored = getWidgetValue(values, registration.dataPath, registration.widgetId);
2306
+ const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
2307
+ if (!Array.isArray(hierarchy)) {
2308
+ return undefined;
2309
+ }
2310
+ const levelData = hierarchy.find((entry) => entry.level === registration.level);
2311
+ if (levelData && String(levelData.level_value_id) === String(valueId)) {
2312
+ return levelData.level_value_mnemonic ? String(levelData.level_value_mnemonic) : undefined;
2313
+ }
2314
+ return undefined;
2315
+ }
2316
+ /** Resolve display mnemonic from cached dropdown options, then stored hierarchy. */
2317
+ function createGeoLevelMnemonicResolver(values, dataSources) {
2318
+ return (registration, valueId) => {
2319
+ const options = dataSources[registration.widgetId];
2320
+ const option = options?.find((entry) => String(entry.value) === String(valueId));
2321
+ if (option?.label) {
2322
+ return option.label;
2323
+ }
2324
+ return resolveStoredMnemonic(values, registration, valueId);
2325
+ };
2326
+ }
2327
+ /** Rebuild group hierarchy from widget values in parent→child order; stop at first missing level. */
2328
+ function rebuildGeoHierarchyFromRegistrations(groupId, values, registrations, resolveMnemonic) {
2329
+ const ordered = orderGeoWidgetRegistrations(registrations.filter((entry) => entry.groupId === groupId));
2330
+ geoHierarchyBuilder.clear(groupId);
2331
+ for (const registration of ordered) {
2332
+ const rawValue = resolveGeoWidgetLevelValue(values, registration.widgetId, registration.dataPath, registration.geoConfig);
2333
+ const valueId = resolveLevelValueId(rawValue);
2334
+ if (!valueId) {
2335
+ break;
2336
+ }
2337
+ const mnemonic = resolveMnemonic?.(registration, valueId) ??
2338
+ resolveStoredMnemonic(values, registration, valueId) ??
2339
+ valueId;
2340
+ geoHierarchyBuilder.addLevel(registration.level, valueId, mnemonic, groupId);
2341
+ }
2342
+ return geoHierarchyBuilder.buildHierarchyJson(groupId) !== null;
2343
+ }
2344
+ function collectGeoWidgetRegistrationsFromWidgets(widgets, namespace) {
2345
+ return widgets
2346
+ .filter((widget) => widget['widget-geo-config'] && typeof widget['widget-data-path'] === 'string')
2347
+ .map((widget) => {
2348
+ const originalWidgetId = widget['widget-id'];
2349
+ const originalDataPath = widget['widget-data-path'];
2350
+ const geoConfig = widget['widget-geo-config'];
2351
+ const widgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
2352
+ const parentWidgetId = geoConfig.parentWidgetId?.trim()
2353
+ ? (namespace ? `${namespace}__${geoConfig.parentWidgetId}` : geoConfig.parentWidgetId)
2354
+ : null;
2355
+ const dataPath = namespace ? `${namespace}.${originalDataPath}` : originalDataPath;
2356
+ return {
2357
+ widgetId,
2358
+ parentWidgetId,
2359
+ level: geoConfig.level,
2360
+ geoConfig,
2361
+ dataPath,
2362
+ groupId: getGeoGroupId(dataPath),
2363
+ };
2364
+ });
2365
+ }
2366
+ /** Reconcile all geo groups in section values before save. */
2367
+ function reconcileGeoHierarchiesInValues(values, registrations, dataSources = {}) {
2368
+ const groupIds = [...new Set(registrations.map((entry) => entry.groupId))];
2369
+ let updatedValues = values;
2370
+ const resolveMnemonic = createGeoLevelMnemonicResolver(updatedValues, dataSources);
2371
+ for (const groupId of groupIds) {
2372
+ const groupRegistrations = registrations.filter((entry) => entry.groupId === groupId);
2373
+ const dataPath = groupRegistrations[0]?.dataPath;
2374
+ const widgetId = groupRegistrations[0]?.widgetId;
2375
+ if (!dataPath || !widgetId) {
2376
+ continue;
2377
+ }
2378
+ rebuildGeoHierarchyFromRegistrations(groupId, updatedValues, groupRegistrations, resolveMnemonic);
2379
+ updatedValues = applySharedGeoHierarchyToValues(updatedValues, groupId, dataPath, widgetId);
2380
+ }
2381
+ return updatedValues;
2382
+ }
2383
+ function getGeoWidgetRegistrationsInGroup(groupId) {
2384
+ return orderGeoWidgetRegistrations([...geoWidgetConfigRegistry.values()].filter((entry) => entry.groupId === groupId));
2385
+ }
2253
2386
  /** True when changedWidgetId is any upstream geo parent of widgetId (not only immediate parent). */
2254
2387
  function isUpstreamGeoAncestor(changedWidgetId, widgetId, immediateParentWidgetId) {
2255
2388
  if (changedWidgetId === widgetId) {
@@ -2344,7 +2477,7 @@ function resetAndSeedGeoHierarchyFromValues(values, dataPath, widgetId, groupId)
2344
2477
 
2345
2478
  // Define stable empty arrays to avoid selector reference issues
2346
2479
  const EMPTY_ERRORS = [];
2347
- const EMPTY_DATA_SOURCE$1 = [];
2480
+ const EMPTY_DATA_SOURCE = [];
2348
2481
  const useBaseWidget = (options) => {
2349
2482
  const { config, dataSourceRequestHandler: propHandler, schemaData, onValueChange } = options;
2350
2483
  const dispatch = reactRedux.useDispatch();
@@ -2359,7 +2492,7 @@ const useBaseWidget = (options) => {
2359
2492
  const errors = reactRedux.useSelector((state) => state.widget.errors[widgetId] ?? EMPTY_ERRORS);
2360
2493
  const touched = reactRedux.useSelector((state) => state.widget.touched[widgetId] || false);
2361
2494
  const loading = reactRedux.useSelector((state) => state.widget.loading[widgetId] || false);
2362
- const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE$1);
2495
+ const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE);
2363
2496
  // Skip value handling for layout widgets (they don't store data values)
2364
2497
  // Infer layout from widget-type
2365
2498
  const isLayoutWidget = config['widget-type'] === 'layout';
@@ -2681,6 +2814,8 @@ const useBaseWidget = (options) => {
2681
2814
  const apiService = dataSource?.type === 'api' ? dataSource.service : '';
2682
2815
  const apiEndpoint = dataSource?.type === 'api' ? dataSource.endpoint : '';
2683
2816
  const configKey = `${widgetId}-${isReadonly}-${dataSource?.type || 'none'}-${apiService}-${apiEndpoint}`;
2817
+ // Stable key so inline schemaData objects (e.g. dialog-table fields) don't retrigger loads every render
2818
+ const schemaDataKey = React.useMemo(() => (schemaData ? JSON.stringify(schemaData) : ''), [schemaData]);
2684
2819
  // Extract dependency value using a granular selector to prevent unnecessary re-renders
2685
2820
  // and infinite loops when other unrelated values in the state change.
2686
2821
  const dependencyValue = reactRedux.useSelector((state) => {
@@ -2798,7 +2933,7 @@ const useBaseWidget = (options) => {
2798
2933
  loadDataSource();
2799
2934
  // Use configKey and dependencyValue to ensure effect runs only when relevant state changes
2800
2935
  // eslint-disable-next-line react-hooks/exhaustive-deps
2801
- }, [configKey, dependencyValue, dataSourceRequestHandler, schemaData, widgetId, dispatch]);
2936
+ }, [configKey, dependencyValue, dataSourceRequestHandler, schemaDataKey, widgetId, dispatch]);
2802
2937
  const geoDisplayLabel = React.useMemo(() => {
2803
2938
  if (!geoConfig) {
2804
2939
  return undefined;
@@ -2887,8 +3022,6 @@ const useWidgetCascade = (options) => {
2887
3022
  }, [cascadeConfig, eventBus, dataSource, widgetId, dispatch]);
2888
3023
  };
2889
3024
 
2890
- // Define stable empty array to avoid selector reference issues
2891
- const EMPTY_DATA_SOURCE = [];
2892
3025
  /**
2893
3026
  * Hook for geo widget cascade functionality
2894
3027
  * Handles geo hierarchy building and cascade behavior
@@ -2918,15 +3051,15 @@ const useGeoWidgetCascade = (options) => {
2918
3051
  ? resolveGeoWidgetLevelValue(state.widget.values, widgetId, dataPath, geoConfig)
2919
3052
  : state.widget.values[widgetId]);
2920
3053
  // Memoize selector to avoid returning new array reference
2921
- const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE);
3054
+ const allDataSources = reactRedux.useSelector((state) => state.widget.dataSources);
2922
3055
  // Register parent chain for upstream-ancestor detection (grandparent → grandchild reset)
2923
3056
  React.useEffect(() => {
2924
- if (!geoConfig) {
3057
+ if (!geoConfig || typeof dataPath !== 'string') {
2925
3058
  return;
2926
3059
  }
2927
- registerGeoWidgetParent(widgetId, geoConfig.parentWidgetId);
2928
- return () => unregisterGeoWidgetParent(widgetId);
2929
- }, [widgetId, geoConfig]);
3060
+ registerGeoWidget(widgetId, geoConfig, dataPath);
3061
+ return () => unregisterGeoWidget(widgetId);
3062
+ }, [widgetId, geoConfig, dataPath]);
2930
3063
  // Keep in-memory builder in sync with persisted hierarchy (reload, cancel→re-edit, etc.)
2931
3064
  React.useEffect(() => {
2932
3065
  if (!geoConfig || typeof dataPath !== 'string') {
@@ -3018,18 +3151,20 @@ const useGeoWidgetCascade = (options) => {
3018
3151
  }, [geoConfig, eventBus, dataSource, widgetId, dataPath, dispatch, groupId]);
3019
3152
  // Handle value changes to build hierarchy
3020
3153
  React.useEffect(() => {
3021
- if (!geoConfig) {
3154
+ if (!geoConfig || typeof dataPath !== 'string') {
3022
3155
  return;
3023
3156
  }
3024
- // Skip if value is undefined (it might still be loading or rehydrating)
3157
+ const { level, isLastLevel } = geoConfig;
3158
+ const groupRegistrations = getGeoWidgetRegistrationsInGroup(groupId);
3159
+ const applyGroupRebuild = () => {
3160
+ const resolveMnemonic = createGeoLevelMnemonicResolver(valuesRef.current, allDataSources);
3161
+ rebuildGeoHierarchyFromRegistrations(groupId, valuesRef.current, groupRegistrations, resolveMnemonic);
3162
+ dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
3163
+ };
3025
3164
  // ONLY clear hierarchy if the value is explicitly null or empty string (user action)
3026
3165
  if (currentValue === null || currentValue === '') {
3027
- const { level, isLastLevel } = geoConfig;
3028
3166
  geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
3029
- // If we have a dataPath, we need to update Redux with the cleared hierarchy
3030
- if (dataPath) {
3031
- dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
3032
- }
3167
+ applyGroupRebuild();
3033
3168
  if (!isLastLevel && eventBus && lastCascadePublishRef.current !== GEO_LEVEL_CLEARED) {
3034
3169
  lastCascadePublishRef.current = GEO_LEVEL_CLEARED;
3035
3170
  eventBus.publish({
@@ -3042,56 +3177,13 @@ const useGeoWidgetCascade = (options) => {
3042
3177
  return;
3043
3178
  }
3044
3179
  if (currentValue === undefined) {
3045
- return; // Skip if undefined (still initializing)
3046
- }
3047
- const { level, isLastLevel } = geoConfig;
3048
- // Check if hierarchy is already built to prevent endless loops
3049
- if (dataPath) {
3050
- const currentHierarchy = getWidgetValue(valuesRef.current, dataPath, widgetId);
3051
- // If hierarchy JSON is already set and matches current value, skip rebuilding
3052
- if (currentHierarchy && typeof currentHierarchy === 'object') {
3053
- // Check if this specific level's value matches the hierarchy
3054
- const hierarchyArray = currentHierarchy.hierarchy || currentHierarchy.geo_code_hierarchy_json?.hierarchy;
3055
- if (Array.isArray(hierarchyArray)) {
3056
- const currentLevelValue = typeof currentValue === 'object'
3057
- ? (currentValue.level_value_id || currentValue.id || currentValue.value)
3058
- : currentValue;
3059
- const levelData = hierarchyArray.find((l) => l.level === geoConfig.level);
3060
- // If this level is already correctly represented in the hierarchy, skip rebuilding
3061
- // String conversion ensures comparison works for mixed types
3062
- if (levelData && String(levelData.level_value_id) === String(currentLevelValue)) {
3063
- return;
3064
- }
3065
- }
3180
+ const hasOwnValue = Object.prototype.hasOwnProperty.call(valuesRef.current, widgetId);
3181
+ if (!hasOwnValue) {
3182
+ return;
3066
3183
  }
3067
3184
  }
3068
- // Extract level_value_id and level_value_mnemonic from current value
3069
- // The value could be the ID itself or an object with id/name
3070
- let level_value_id;
3071
- let level_value_mnemonic;
3072
- if (typeof currentValue === 'string' || typeof currentValue === 'number') {
3073
- // Value is just the ID, need to find mnemonic from data source
3074
- level_value_id = String(currentValue);
3075
- // Try to get mnemonic from data source options
3076
- const option = dataSourceOptions.find((opt) => opt.value === currentValue);
3077
- level_value_mnemonic = option?.label || String(currentValue);
3078
- }
3079
- else if (currentValue && typeof currentValue === 'object') {
3080
- level_value_id = currentValue.level_value_id || currentValue.id || currentValue.value;
3081
- level_value_mnemonic = currentValue.level_value_mnemonic || currentValue.name || currentValue.label;
3082
- }
3083
- else {
3084
- return;
3085
- }
3086
- // When a widget's own value changes, remove this level and all below from hierarchy first
3087
- geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
3088
- // Add level to hierarchy
3089
- geoHierarchyBuilder.addLevel(level, level_value_id, level_value_mnemonic, groupId);
3090
- // Build and store hierarchy JSON on every change
3091
- if (dataPath && geoHierarchyBuilder.buildHierarchyJson(groupId)) {
3092
- dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
3093
- }
3094
- }, [geoConfig, currentValue, widgetId, dataPath, dispatch, dataSourceOptions, groupId]);
3185
+ applyGroupRebuild();
3186
+ }, [geoConfig, currentValue, widgetId, dataPath, dispatch, allDataSources, groupId, eventBus]);
3095
3187
  };
3096
3188
 
3097
3189
  class WidgetRegistry {
@@ -4993,7 +5085,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
4993
5085
  // This ensures we use the original widget IDs and data paths
4994
5086
  const sectionWidgets = collectWidgets(originalSection.panels);
4995
5087
  const currentState = store.getState().widget;
4996
- const currentSchemaData = currentState.values || {};
5088
+ let currentSchemaData = currentState.values || {};
5089
+ const geoRegistrations = collectGeoWidgetRegistrationsFromWidgets(sectionWidgets, namespace);
5090
+ if (geoRegistrations.length > 0) {
5091
+ currentSchemaData = reconcileGeoHierarchiesInValues(currentSchemaData, geoRegistrations, currentState.dataSources || {});
5092
+ dispatch(setValues(currentSchemaData));
5093
+ }
4997
5094
  const isSectionValid = sectionValidate(originalSection, currentSchemaData, dispatch, true);
4998
5095
  if (!isSectionValid) {
4999
5096
  return;
@@ -5059,7 +5156,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
5059
5156
  if (isDraft !== false && store && onSectionSave) {
5060
5157
  const sectionWidgets = collectWidgets(originalSection.panels);
5061
5158
  const currentState = store.getState().widget;
5062
- const currentSchemaData = currentState.values || {};
5159
+ let currentSchemaData = currentState.values || {};
5160
+ const geoRegistrations = collectGeoWidgetRegistrationsFromWidgets(sectionWidgets, namespace);
5161
+ if (geoRegistrations.length > 0) {
5162
+ currentSchemaData = reconcileGeoHierarchiesInValues(currentSchemaData, geoRegistrations, currentState.dataSources || {});
5163
+ dispatch(setValues(currentSchemaData));
5164
+ }
5063
5165
  const isSectionValid = sectionValidate(originalSection, currentSchemaData, dispatch, true);
5064
5166
  if (!isSectionValid)
5065
5167
  return;
@@ -9987,6 +10089,22 @@ const TableWidget = ({ config }) => {
9987
10089
  };
9988
10090
 
9989
10091
  const isUnsetRowValue = (value) => value === null || value === undefined || value === '';
10092
+ /** Match TableWidget cell styling for add / update / delete rows */
10093
+ const getRowCellStyle = (editAction) => {
10094
+ if (editAction === 'ADD') {
10095
+ return { color: 'var(--owt-color-success, #16A34A)' };
10096
+ }
10097
+ if (editAction === 'DELETE') {
10098
+ return {
10099
+ color: 'var(--owt-color-error, #B91C1C)',
10100
+ textDecoration: 'line-through',
10101
+ };
10102
+ }
10103
+ if (editAction === 'UPDATE') {
10104
+ return { color: 'var(--owt-color-warning, #F59E0B)' };
10105
+ }
10106
+ return {};
10107
+ };
9990
10108
  // Display select value label in view mode
9991
10109
  const SelectDisplayValue = ({ config, value }) => {
9992
10110
  const { dataSourceOptions, loading } = useBaseWidget({ config });
@@ -9997,23 +10115,29 @@ const SelectDisplayValue = ({ config, value }) => {
9997
10115
  const selectedOption = dataSourceOptions.find((option) => option.value === value || String(option.value) === String(value));
9998
10116
  return jsxRuntimeExports.jsx("span", { children: selectedOption ? selectedOption.label : String(value) });
9999
10117
  };
10118
+ /** Isolated dialog field — avoids re-running data-source effects when sibling fields update. */
10119
+ const DialogTableField = React.memo(function DialogTableField({ col, cellWidgetId, dialogRowValues, isReadonly, }) {
10120
+ const widgetType = col.widget || 'text';
10121
+ const fieldConfig = React.useMemo(() => {
10122
+ return {
10123
+ ...col,
10124
+ widget: widgetType,
10125
+ 'widget-type': col['widget-type'] || 'input',
10126
+ 'widget-id': cellWidgetId,
10127
+ 'widget-label': col['widget-label'],
10128
+ 'widget-readonly': isReadonly || col['widget-readonly'] === true,
10129
+ 'widget-data-path': undefined,
10130
+ 'widget-data-default': col['widget-data-default'],
10131
+ 'widget-data-options': undefined,
10132
+ 'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
10133
+ };
10134
+ }, [col, cellWidgetId, dialogRowValues, isReadonly, widgetType]);
10135
+ return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig }) }));
10136
+ });
10000
10137
  /**
10001
10138
  * Dialog table widget:
10002
10139
  * - Table displays a subset of columns (n out of x)
10003
10140
  * - Add/Edit happens in a modal dialog that shows ALL columns as a form
10004
- *
10005
- * Usage in schema:
10006
- * {
10007
- * "widget": "dialog-table",
10008
- * "widget-type": "table",
10009
- * "widget-label": "Household Members",
10010
- * "widget-id": "householdMembers",
10011
- * "widget-data-path": "household.members",
10012
- * "widget-data-columns": [ ...all columns... ],
10013
- * "widget-data-visible-columns": ["firstName", "lastName", "dob"], // optional override; default = by column flag
10014
- * // Per-column control (recommended): set "column-visible-in-table": false to hide it in the table
10015
- * "widget-data-operations": { "add": true, "edit": true, "remove": true }
10016
- * }
10017
10141
  */
10018
10142
  const DialogTableWidget = ({ config }) => {
10019
10143
  const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
@@ -10023,23 +10147,22 @@ const DialogTableWidget = ({ config }) => {
10023
10147
  const columns = widgetConfig['widget-data-columns'] || [];
10024
10148
  const operations = widgetConfig['widget-data-operations'] || {};
10025
10149
  const isReadonly = widgetConfig['widget-readonly'] || false;
10150
+ // Soft-delete (keep row, red + strikethrough) whenever remove is allowed — matches TableWidget
10151
+ const shouldSoftDeleteOnRemove = !isReadonly && !!operations.remove;
10026
10152
  const visibleColumnKeys = widgetConfig['widget-data-visible-columns'];
10027
10153
  const visibleColumns = React.useMemo(() => {
10028
- // 1) If explicit list provided, it wins
10029
10154
  if (Array.isArray(visibleColumnKeys) && visibleColumnKeys.length > 0) {
10030
10155
  const keySet = new Set(visibleColumnKeys);
10031
10156
  return columns.filter((c) => keySet.has(c['column-key']));
10032
10157
  }
10033
- // 2) Otherwise decide per column (default = visible)
10034
10158
  return columns.filter((c) => c['column-visible-in-table'] !== false);
10035
10159
  }, [columns, visibleColumnKeys]);
10036
10160
  const [dialogOpen, setDialogOpen] = React.useState(false);
10037
10161
  const [dialogMode, setDialogMode] = React.useState('add');
10038
10162
  const [activeRowIndex, setActiveRowIndex] = React.useState(null);
10039
- const [formData, setFormData] = React.useState({});
10040
- /** Unique per dialog open so Redux widget ids don't reuse stale values across rows/add sessions */
10041
10163
  const dialogSessionRef = React.useRef(0);
10042
10164
  const [dialogSessionId, setDialogSessionId] = React.useState(0);
10165
+ const membersWidgetId = widgetConfig['widget-id'];
10043
10166
  const addDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-add']) ||
10044
10167
  translate('table.addRecordDialog') ||
10045
10168
  'Add record';
@@ -10059,15 +10182,26 @@ const DialogTableWidget = ({ config }) => {
10059
10182
  });
10060
10183
  return emptyRow;
10061
10184
  }, [columns]);
10062
- const dialogFieldWidgetId = React.useCallback((columnKey) => `${widgetConfig['widget-id']}-dlg-${dialogSessionId}-${columnKey}`, [widgetConfig, dialogSessionId]);
10185
+ const dialogFieldWidgetId = React.useCallback((sessionId, columnKey) => `${membersWidgetId}-dlg-${sessionId}-${columnKey}`, [membersWidgetId]);
10063
10186
  const resetDialogWidgets = React.useCallback((sessionId) => {
10064
10187
  if (sessionId <= 0)
10065
10188
  return;
10066
10189
  columns.forEach((col) => {
10067
- const wid = `${widgetConfig['widget-id']}-dlg-${sessionId}-${col['column-key']}`;
10068
- dispatch(resetWidget(wid));
10190
+ dispatch(resetWidget(dialogFieldWidgetId(sessionId, col['column-key'])));
10191
+ });
10192
+ }, [columns, dialogFieldWidgetId, dispatch]);
10193
+ const seedDialogReduxValues = React.useCallback((sessionId, rowData) => {
10194
+ const seeds = {};
10195
+ columns.forEach((col) => {
10196
+ const key = col['column-key'];
10197
+ if (rowData[key] !== undefined) {
10198
+ seeds[dialogFieldWidgetId(sessionId, key)] = rowData[key];
10199
+ }
10069
10200
  });
10070
- }, [columns, widgetConfig, dispatch]);
10201
+ if (Object.keys(seeds).length > 0) {
10202
+ dispatch(setValues(seeds));
10203
+ }
10204
+ }, [columns, dialogFieldWidgetId, dispatch]);
10071
10205
  const beginDialogSession = React.useCallback(() => {
10072
10206
  dialogSessionRef.current += 1;
10073
10207
  const nextSession = dialogSessionRef.current;
@@ -10076,15 +10210,21 @@ const DialogTableWidget = ({ config }) => {
10076
10210
  }, []);
10077
10211
  const openAddDialog = React.useCallback(() => {
10078
10212
  resetDialogWidgets(dialogSessionId);
10079
- beginDialogSession();
10213
+ const sessionId = beginDialogSession();
10214
+ seedDialogReduxValues(sessionId, buildEmptyRow());
10080
10215
  setDialogMode('add');
10081
10216
  setActiveRowIndex(null);
10082
- setFormData(buildEmptyRow());
10083
10217
  setDialogOpen(true);
10084
- }, [buildEmptyRow, beginDialogSession, resetDialogWidgets, dialogSessionId]);
10218
+ }, [
10219
+ buildEmptyRow,
10220
+ beginDialogSession,
10221
+ resetDialogWidgets,
10222
+ dialogSessionId,
10223
+ seedDialogReduxValues,
10224
+ ]);
10085
10225
  const openEditDialog = React.useCallback((rowIndex) => {
10086
10226
  resetDialogWidgets(dialogSessionId);
10087
- beginDialogSession();
10227
+ const sessionId = beginDialogSession();
10088
10228
  const row = rows[rowIndex] || {};
10089
10229
  const nextFormData = buildEmptyRow();
10090
10230
  columns.forEach((col) => {
@@ -10092,23 +10232,26 @@ const DialogTableWidget = ({ config }) => {
10092
10232
  if (row[key] !== undefined)
10093
10233
  nextFormData[key] = row[key];
10094
10234
  });
10235
+ seedDialogReduxValues(sessionId, nextFormData);
10095
10236
  setDialogMode('edit');
10096
10237
  setActiveRowIndex(rowIndex);
10097
- setFormData(nextFormData);
10098
10238
  setDialogOpen(true);
10099
- }, [rows, columns, buildEmptyRow, resetDialogWidgets, dialogSessionId, beginDialogSession]);
10239
+ }, [
10240
+ rows,
10241
+ columns,
10242
+ buildEmptyRow,
10243
+ resetDialogWidgets,
10244
+ dialogSessionId,
10245
+ beginDialogSession,
10246
+ seedDialogReduxValues,
10247
+ ]);
10100
10248
  const closeDialog = React.useCallback(() => {
10101
10249
  const sessionToClear = dialogSessionId;
10102
10250
  setDialogOpen(false);
10103
10251
  setActiveRowIndex(null);
10104
- setFormData({});
10105
10252
  resetDialogWidgets(sessionToClear);
10106
10253
  setDialogSessionId(0);
10107
10254
  }, [dialogSessionId, resetDialogWidgets]);
10108
- const updateField = React.useCallback((columnKey, newValue) => {
10109
- setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
10110
- }, []);
10111
- const membersWidgetId = widgetConfig['widget-id'];
10112
10255
  const dialogStoreValues = reactRedux.useSelector((state) => {
10113
10256
  if (dialogSessionId <= 0) {
10114
10257
  return {};
@@ -10117,25 +10260,15 @@ const DialogTableWidget = ({ config }) => {
10117
10260
  const row = {};
10118
10261
  columns.forEach((col) => {
10119
10262
  const k = col['column-key'];
10120
- const wid = `${membersWidgetId}-dlg-${dialogSessionId}-${k}`;
10263
+ const wid = dialogFieldWidgetId(dialogSessionId, k);
10121
10264
  if (values[wid] !== undefined) {
10122
10265
  row[k] = values[wid];
10123
10266
  }
10124
10267
  });
10125
10268
  return row;
10126
- }, (a, b) => JSON.stringify(a) === JSON.stringify(b));
10127
- const buildDialogRowValues = React.useCallback((storeSlice) => {
10128
- const row = { ...formData };
10129
- columns.forEach((col) => {
10130
- const k = col['column-key'];
10131
- if (storeSlice[k] !== undefined) {
10132
- row[k] = storeSlice[k];
10133
- }
10134
- });
10135
- return row;
10136
- }, [formData, columns]);
10137
- const dialogRowValues = React.useMemo(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
10138
- const collectMergedRowPayload = React.useCallback(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
10269
+ });
10270
+ const dialogRowValues = dialogStoreValues;
10271
+ const collectMergedRowPayload = React.useCallback(() => dialogStoreValues, [dialogStoreValues]);
10139
10272
  const finalizeDialogRowPayload = React.useCallback((raw) => {
10140
10273
  const result = {};
10141
10274
  columns.forEach((col) => {
@@ -10155,7 +10288,7 @@ const DialogTableWidget = ({ config }) => {
10155
10288
  let hasErrors = false;
10156
10289
  columns.forEach((col) => {
10157
10290
  const key = col['column-key'];
10158
- const cellWidgetId = dialogFieldWidgetId(key);
10291
+ const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
10159
10292
  const isColReadonly = isReadonly || col['widget-readonly'] === true;
10160
10293
  if (isColReadonly)
10161
10294
  return;
@@ -10199,11 +10332,32 @@ const DialogTableWidget = ({ config }) => {
10199
10332
  onChange(newRows);
10200
10333
  closeDialog();
10201
10334
  }
10202
- }, [collectMergedRowPayload, finalizeDialogRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
10335
+ }, [
10336
+ collectMergedRowPayload,
10337
+ finalizeDialogRowPayload,
10338
+ dialogMode,
10339
+ onChange,
10340
+ rows,
10341
+ closeDialog,
10342
+ activeRowIndex,
10343
+ columns,
10344
+ dialogSessionId,
10345
+ dialogFieldWidgetId,
10346
+ isReadonly,
10347
+ dispatch,
10348
+ ]);
10203
10349
  const deleteRow = React.useCallback((rowIndex) => {
10204
- const newRows = rows.filter((_, i) => i !== rowIndex);
10205
- onChange(newRows);
10206
- }, [rows, onChange]);
10350
+ if (shouldSoftDeleteOnRemove) {
10351
+ const newRows = [...rows];
10352
+ newRows[rowIndex] = {
10353
+ ...newRows[rowIndex],
10354
+ edit_action: 'DELETE',
10355
+ };
10356
+ onChange(newRows);
10357
+ return;
10358
+ }
10359
+ onChange(rows.filter((_, i) => i !== rowIndex));
10360
+ }, [rows, onChange, shouldSoftDeleteOnRemove]);
10207
10361
  const getDisplayValue = React.useCallback((rowIndex, column) => {
10208
10362
  const key = column['column-key'];
10209
10363
  const cellValue = rows[rowIndex]?.[key];
@@ -10211,11 +10365,12 @@ const DialogTableWidget = ({ config }) => {
10211
10365
  if (cellValue === null || cellValue === undefined || cellValue === '')
10212
10366
  return '-';
10213
10367
  if (widgetType === 'select')
10214
- return null; // handled by SelectDisplayValue
10368
+ return null;
10215
10369
  if (column['widget-data-format'])
10216
10370
  return formatValue(cellValue, column['widget-data-format'], column.widget);
10217
10371
  return String(cellValue);
10218
10372
  }, [rows]);
10373
+ const visibleDialogColumns = React.useMemo(() => columns.filter((col) => shouldShowWidget(col['widget-data-options'], dialogRowValues)), [columns, dialogRowValues]);
10219
10374
  const tableWidgetId = `dialog-table-widget-${widgetConfig['widget-id']}`;
10220
10375
  const columnSpan = widgetConfig['widget-column-span'] || 2;
10221
10376
  const minWidth = columnSpan * 200;
@@ -10243,37 +10398,40 @@ const DialogTableWidget = ({ config }) => {
10243
10398
  }, children: translate('table.addRecord') || 'Add New Record' }) })), jsxRuntimeExports.jsx("div", { className: "overflow-x-auto border", style: {
10244
10399
  borderRadius: 'var(--owt-widget-table-border-radius, 15px)',
10245
10400
  borderColor: 'var(--owt-widget-table-border-color, #C4C4C4)',
10246
- }, children: jsxRuntimeExports.jsxs("table", { className: "min-w-full", style: { borderCollapse: 'separate', borderSpacing: 0 }, children: [jsxRuntimeExports.jsx("thead", { style: { backgroundColor: 'var(--owt-widget-table-header-bg, #F6F6F6)' }, children: jsxRuntimeExports.jsxs("tr", { style: { borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)' }, children: [visibleColumns.map((col) => (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translateConfig(col['widget-label']) }, col['column-key']))), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translate('common.actions') || 'Actions' }))] }) }), jsxRuntimeExports.jsxs("tbody", { style: { backgroundColor: 'var(--owt-widget-table-body-bg, #FFFFFF)' }, children: [rows.length === 0 && (jsxRuntimeExports.jsx("tr", { children: jsxRuntimeExports.jsxs("td", { colSpan: visibleColumns.length + (((operations.edit || operations.remove) && !isReadonly) ? 1 : 0), className: "px-4 py-6 text-center text-sm", style: { color: 'var(--owt-widget-table-empty-color, #727474)' }, children: [translate('table.noData') || 'No records available.', operations.add && !isReadonly && ` ${translate('table.clickToAdd') || 'Click "Add New Record" to add one.'}`] }) })), rows.map((row, rowIndex) => (jsxRuntimeExports.jsxs("tr", { style: {
10247
- borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
10248
- backgroundColor: row?.edit_action === 'DELETE'
10249
- ? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
10250
- : undefined,
10251
- }, children: [visibleColumns.map((col) => {
10252
- const key = col['column-key'];
10253
- const widgetType = col.widget || 'text';
10254
- const displayValue = getDisplayValue(rowIndex, col);
10255
- if (widgetType === 'select' && displayValue === null) {
10256
- const displayConfig = {
10257
- ...col,
10258
- 'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
10259
- 'widget-label': '',
10260
- 'widget-readonly': true,
10261
- 'widget-data-path': undefined,
10262
- };
10263
- return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: displayConfig, value: row?.[key] }) }) }, key));
10264
- }
10265
- return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: displayValue }) }, key));
10266
- }), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", style: { minWidth: '120px' }, children: jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [operations.edit && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => openEditDialog(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
10267
- borderRadius: 'var(--owt-btn-border-radius, 10px)',
10268
- color: 'var(--owt-color-primary-dark, #F07B1A)',
10269
- backgroundColor: 'transparent',
10270
- border: 'none',
10271
- }, children: translate('common.edit') || 'Edit' })), operations.remove && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => deleteRow(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
10272
- borderRadius: 'var(--owt-btn-border-radius, 10px)',
10273
- color: 'var(--owt-color-error, #B91C1C)',
10274
- backgroundColor: 'transparent',
10275
- border: 'none',
10276
- }, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex)))] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] }), dialogOpen && (jsxRuntimeExports.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50", style: { backgroundColor: 'rgba(0,0,0,0.5)' }, children: jsxRuntimeExports.jsxs("div", { className: "rounded-lg p-6 w-full mx-4", style: {
10401
+ }, children: jsxRuntimeExports.jsxs("table", { className: "min-w-full", style: { borderCollapse: 'separate', borderSpacing: 0 }, children: [jsxRuntimeExports.jsx("thead", { style: { backgroundColor: 'var(--owt-widget-table-header-bg, #F6F6F6)' }, children: jsxRuntimeExports.jsxs("tr", { style: { borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)' }, children: [visibleColumns.map((col) => (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translateConfig(col['widget-label']) }, col['column-key']))), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translate('common.actions') || 'Actions' }))] }) }), jsxRuntimeExports.jsxs("tbody", { style: { backgroundColor: 'var(--owt-widget-table-body-bg, #FFFFFF)' }, children: [rows.length === 0 && (jsxRuntimeExports.jsx("tr", { children: jsxRuntimeExports.jsxs("td", { colSpan: visibleColumns.length + (((operations.edit || operations.remove) && !isReadonly) ? 1 : 0), className: "px-4 py-6 text-center text-sm", style: { color: 'var(--owt-widget-table-empty-color, #727474)' }, children: [translate('table.noData') || 'No records available.', operations.add && !isReadonly && ` ${translate('table.clickToAdd') || 'Click "Add New Record" to add one.'}`] }) })), rows.map((row, rowIndex) => {
10402
+ const cellStyle = getRowCellStyle(row?.edit_action);
10403
+ return (jsxRuntimeExports.jsxs("tr", { style: {
10404
+ borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
10405
+ backgroundColor: row?.edit_action === 'DELETE'
10406
+ ? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
10407
+ : undefined,
10408
+ }, children: [visibleColumns.map((col) => {
10409
+ const key = col['column-key'];
10410
+ const widgetType = col.widget || 'text';
10411
+ const displayValue = getDisplayValue(rowIndex, col);
10412
+ if (widgetType === 'select' && displayValue === null) {
10413
+ const displayConfig = {
10414
+ ...col,
10415
+ 'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
10416
+ 'widget-label': '',
10417
+ 'widget-readonly': true,
10418
+ 'widget-data-path': undefined,
10419
+ };
10420
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: displayConfig, value: row?.[key] }) }) }, key));
10421
+ }
10422
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: displayValue }) }, key));
10423
+ }), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", style: { minWidth: '120px' }, children: jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [operations.edit && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => openEditDialog(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
10424
+ borderRadius: 'var(--owt-btn-border-radius, 10px)',
10425
+ color: 'var(--owt-color-primary-dark, #F07B1A)',
10426
+ backgroundColor: 'transparent',
10427
+ border: 'none',
10428
+ }, children: translate('common.edit') || 'Edit' })), operations.remove && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => deleteRow(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
10429
+ borderRadius: 'var(--owt-btn-border-radius, 10px)',
10430
+ color: 'var(--owt-color-error, #B91C1C)',
10431
+ backgroundColor: 'transparent',
10432
+ border: 'none',
10433
+ }, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex));
10434
+ })] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] }), dialogOpen && (jsxRuntimeExports.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50", style: { backgroundColor: 'rgba(0,0,0,0.5)' }, children: jsxRuntimeExports.jsxs("div", { className: "rounded-lg p-6 w-full mx-4", style: {
10277
10435
  maxWidth: '900px',
10278
10436
  backgroundColor: 'var(--owt-color-bg, #FFFFFF)',
10279
10437
  borderRadius: 'var(--owt-widget-card-border-radius, 20px)',
@@ -10284,27 +10442,10 @@ const DialogTableWidget = ({ config }) => {
10284
10442
  cursor: 'pointer',
10285
10443
  fontSize: '20px',
10286
10444
  lineHeight: 1,
10287
- }, "aria-label": "Close", children: "\u00D7" })] }), jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", style: { maxHeight: '70vh', overflow: 'auto' }, children: columns.map((col) => {
10445
+ }, "aria-label": "Close", children: "\u00D7" })] }), jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", style: { maxHeight: '70vh', overflow: 'auto' }, children: visibleDialogColumns.map((col) => {
10288
10446
  const key = col['column-key'];
10289
- if (!shouldShowWidget(col['widget-data-options'], dialogRowValues)) {
10290
- return null;
10291
- }
10292
- const widgetType = col.widget || 'text';
10293
- const cellWidgetId = dialogFieldWidgetId(key);
10294
- const initialValue = formData[key] ?? col['widget-data-default'];
10295
- const fieldConfig = {
10296
- ...col,
10297
- widget: widgetType,
10298
- 'widget-type': col['widget-type'] || 'input',
10299
- 'widget-id': cellWidgetId,
10300
- 'widget-label': col['widget-label'],
10301
- 'widget-readonly': isReadonly || col['widget-readonly'] === true,
10302
- 'widget-data-path': undefined,
10303
- 'widget-data-default': initialValue,
10304
- 'widget-data-options': undefined,
10305
- 'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
10306
- };
10307
- return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig, schemaData: { [cellWidgetId]: initialValue }, onValueChange: (_widgetId, newValue) => updateField(key, newValue) }) }, `${dialogSessionId}-${key}`));
10447
+ const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
10448
+ return (jsxRuntimeExports.jsx(DialogTableField, { col: col, cellWidgetId: cellWidgetId, dialogRowValues: dialogRowValues, isReadonly: isReadonly }, `${dialogSessionId}-${key}`));
10308
10449
  }) }, `dialog-fields-${dialogSessionId}`), jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3 mt-6", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: closeDialog, className: "px-4 py-2 text-sm font-medium", style: {
10309
10450
  borderRadius: 'var(--owt-btn-border-radius, 10px)',
10310
10451
  border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',
@@ -12988,6 +13129,8 @@ exports.applyCaseControl = applyCaseControl;
12988
13129
  exports.applyDecimalPrecision = applyDecimalPrecision;
12989
13130
  exports.applyMask = applyMask;
12990
13131
  exports.applySharedGeoHierarchyToValues = applySharedGeoHierarchyToValues;
13132
+ exports.collectGeoWidgetRegistrationsFromWidgets = collectGeoWidgetRegistrationsFromWidgets;
13133
+ exports.createGeoLevelMnemonicResolver = createGeoLevelMnemonicResolver;
12991
13134
  exports.createWidgetStore = createWidgetStore;
12992
13135
  exports.createZodSchema = createZodSchema;
12993
13136
  exports.defaultTheme = defaultTheme;
@@ -13005,6 +13148,7 @@ exports.getCachedApiDataSource = getCachedApiDataSource;
13005
13148
  exports.getFormattedNumberLength = getFormattedNumberLength;
13006
13149
  exports.getGeoDescendantWidgetIds = getGeoDescendantWidgetIds;
13007
13150
  exports.getGeoGroupId = getGeoGroupId;
13151
+ exports.getGeoWidgetRegistrationsInGroup = getGeoWidgetRegistrationsInGroup;
13008
13152
  exports.getSchemaDataSource = getSchemaDataSource;
13009
13153
  exports.getStaticDataSource = getStaticDataSource;
13010
13154
  exports.getValueByPath = getValueByPath;
@@ -13015,9 +13159,13 @@ exports.isAllowedKey = isAllowedKey;
13015
13159
  exports.isUpstreamGeoAncestor = isUpstreamGeoAncestor;
13016
13160
  exports.normalizeNumericDefault = normalizeNumericDefault;
13017
13161
  exports.normalizeOptionRules = normalizeOptionRules;
13162
+ exports.orderGeoWidgetRegistrations = orderGeoWidgetRegistrations;
13018
13163
  exports.parseDataPath = parseDataPath;
13019
13164
  exports.parseNumber = parseNumber;
13165
+ exports.rebuildGeoHierarchyFromRegistrations = rebuildGeoHierarchyFromRegistrations;
13166
+ exports.reconcileGeoHierarchiesInValues = reconcileGeoHierarchiesInValues;
13020
13167
  exports.registerDefaultWidgets = registerDefaultWidgets;
13168
+ exports.registerGeoWidget = registerGeoWidget;
13021
13169
  exports.registerGeoWidgetParent = registerGeoWidgetParent;
13022
13170
  exports.removeMask = removeMask;
13023
13171
  exports.resetAll = resetAll;
@@ -13043,6 +13191,7 @@ exports.transformDataSourceOptions = transformDataSourceOptions;
13043
13191
  exports.translatePanelConfig = translatePanelConfig;
13044
13192
  exports.translateUISchema = translateUISchema;
13045
13193
  exports.translateWidgetConfig = translateWidgetConfig;
13194
+ exports.unregisterGeoWidget = unregisterGeoWidget;
13046
13195
  exports.unregisterGeoWidgetParent = unregisterGeoWidgetParent;
13047
13196
  exports.useBaseWidget = useBaseWidget;
13048
13197
  exports.useGeoWidgetCascade = useGeoWidgetCascade;