@openg2p/registry-widgets 0.1.3 → 0.1.5

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.esm.js CHANGED
@@ -950,32 +950,63 @@ const useBaseWidget = (options) => {
950
950
  if (isLayoutWidget) {
951
951
  return undefined; // Layout widgets don't have values
952
952
  }
953
+ // Helper to extract displayable value from object (especially geo hierarchy objects)
954
+ const extractValueFromObject = (obj) => {
955
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
956
+ return obj;
957
+ }
958
+ // Check for geo hierarchy structure first
959
+ if ('geo_code_hierarchy_json' in obj || 'geo_lowest_level_value_id' in obj) {
960
+ if ('geo_lowest_level_value_id' in obj) {
961
+ return obj.geo_lowest_level_value_id;
962
+ }
963
+ // If it's a geo hierarchy object but no extractable ID, return undefined to avoid rendering object
964
+ return undefined;
965
+ }
966
+ // Try common value fields
967
+ if ('value' in obj) {
968
+ return obj.value;
969
+ }
970
+ if ('id' in obj) {
971
+ return obj.id;
972
+ }
973
+ if ('label' in obj) {
974
+ return obj.label;
975
+ }
976
+ if ('name' in obj) {
977
+ return obj.name;
978
+ }
979
+ // If no extractable value found, return undefined to avoid rendering object as React child
980
+ // This prevents "Objects are not valid as a React child" errors
981
+ return undefined;
982
+ };
953
983
  // Try to get value from widgetId first (this should have the actual selected value)
954
984
  // For geo widgets with dataPath, widgetId stores the actual ID, while dataPath stores the hierarchy object
955
985
  let value = values[widgetId];
986
+ // Extract value if it's an object (handles geo hierarchy objects stored in widgetId)
987
+ if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) {
988
+ value = extractValueFromObject(value);
989
+ }
956
990
  // If widgetId doesn't have a value, try dataPath
957
991
  if (value === undefined && config['widget-data-path']) {
958
992
  value = getWidgetValue(values, config['widget-data-path'], widgetId);
959
- // CRITICAL: For geo widgets with dataPath, the value might be stored as a hierarchy object
960
- // Extract the actual value (geo_lowest_level_value_id) if it's an object
961
- const geoConfig = config['widget-geo-config'];
962
- if (geoConfig?.isLastLevel && value && typeof value === 'object' && !Array.isArray(value)) {
963
- // If it's a geo hierarchy object, extract the actual value
964
- if ('geo_lowest_level_value_id' in value) {
965
- value = value.geo_lowest_level_value_id;
966
- }
967
- else if ('value' in value) {
968
- value = value.value;
969
- }
970
- else if ('id' in value) {
971
- value = value.id;
972
- }
993
+ // Extract value if it's an object (handles geo hierarchy objects from dataPath)
994
+ if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) {
995
+ value = extractValueFromObject(value);
973
996
  }
974
997
  }
975
998
  // If value is still undefined and user has set a value, try reading from widgetId as backup
976
999
  // This handles cases where dataPath lookup might fail temporarily
977
1000
  if (value === undefined && userHasSetValueRef.current && values[widgetId] !== undefined) {
978
1001
  value = values[widgetId];
1002
+ // Extract value if it's an object (handles geo hierarchy objects)
1003
+ if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) {
1004
+ value = extractValueFromObject(value);
1005
+ }
1006
+ }
1007
+ // Final safety check: if value is still an object, extract displayable value
1008
+ if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) {
1009
+ value = extractValueFromObject(value);
979
1010
  }
980
1011
  // If user has explicitly set a value, always return it (even if undefined/null)
981
1012
  // This prevents the default from overwriting user selections
@@ -2245,7 +2276,7 @@ const WidgetProvider = ({ store, dataSourceRequestHandler, schemaData, translate
2245
2276
  widgetStore.dispatch(setValues(schemaData));
2246
2277
  }
2247
2278
  // eslint-disable-next-line react-hooks/exhaustive-deps
2248
- }, []); // Only run on mount
2279
+ }, [schemaData, widgetStore]); // Only run on mount
2249
2280
  const content = (jsxRuntimeExports.jsx(Provider, { store: widgetStore, children: jsxRuntimeExports.jsx(WidgetContext.Provider, { value: contextValue, children: jsxRuntimeExports.jsx(WidgetEventBusContext.Provider, { value: eventBus, children: children }) }) }));
2250
2281
  return content;
2251
2282
  };
@@ -2255,8 +2286,11 @@ const WidgetRenderer = ({ config, dataSourceRequestHandler: propDataSourceReques
2255
2286
  const context = useWidgetContext();
2256
2287
  const dataSourceRequestHandler = propDataSourceRequestHandler || context.dataSourceRequestHandler;
2257
2288
  const schemaData = propSchemaData || context.schemaData;
2289
+ // Warn if dataSourceRequestHandler is missing for API data sources, but don't break rendering
2290
+ // This allows widgets to render in read-only or static modes (e.g., CRView)
2258
2291
  if (!dataSourceRequestHandler && config['widget-data-source']?.type === 'api') {
2259
- console.error(`[WidgetRenderer] dataSourceRequestHandler is required for widget ${config['widget-id']} with API data source`);
2292
+ console.warn(`[WidgetRenderer] dataSourceRequestHandler is not provided for widget ${config['widget-id']} with API data source. ` +
2293
+ `The widget will render but API data source functionality will be disabled.`);
2260
2294
  }
2261
2295
  // Get values from Redux for cascade hooks
2262
2296
  const values = useSelector((state) => state.widget.values);
@@ -3192,7 +3226,7 @@ const namespaceSectionConfig = (section, namespace) => {
3192
3226
  * - Panels wrap when they exceed available width
3193
3227
  * - Sections can sit side-by-side if there's space
3194
3228
  */
3195
- const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequestHandler, schemaData, onValueChange, gridColumnSpan, onSectionSave, hideEditButton = false, mode = 'RegistryView', namespace, }) => {
3229
+ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequestHandler, schemaData, onValueChange, gridColumnSpan, onSectionSave, hideEditButton = false, mode = 'RegistryView', namespace, changeRequestType, showChangeRequestLabel = true, }) => {
3196
3230
  const { translateConfig, translate } = useWidgetTranslation();
3197
3231
  const { schemaData: contextSchemaData, dataSourceRequestHandler: contextDataSourceRequestHandler } = useWidgetContext();
3198
3232
  const store = useStore();
@@ -3810,11 +3844,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
3810
3844
  align-items: center;
3811
3845
  gap: 0.5rem;
3812
3846
  }
3813
- ` }), jsxRuntimeExports.jsxs("div", { ref: sectionRef, className: `section ${sectionClassId} px-4 sm:px-6 lg:px-8 border-2 border-gray-300`, "data-section-id": sectionId, "data-has-table": hasTableWidget ? 'true' : 'false', "data-has-explicit-span": hasExplicitTableSpan ? 'true' : 'false', "data-edit-mode": isEditMode ? 'true' : 'false', "data-column-span": columnSpan, style: {
3847
+ ` }), jsxRuntimeExports.jsxs("div", { ref: sectionRef, className: `section ${sectionClassId} px-4 sm:px-6 lg:px-8 border-2 border-white `, "data-section-id": sectionId, "data-has-table": hasTableWidget ? 'true' : 'false', "data-has-explicit-span": hasExplicitTableSpan ? 'true' : 'false', "data-edit-mode": isEditMode ? 'true' : 'false', "data-column-span": columnSpan, "data-change-request-type": changeRequestType, style: {
3814
3848
  gridColumn: `span ${columnSpan}`,
3815
3849
  width: '100%',
3816
3850
  borderRadius: '10px',
3817
- backgroundColor: '#FFFFFF',
3851
+ backgroundColor: changeRequestType === 'old' ? '#F9F9F9' : '#FFFFFF', // Faded background for old change requests
3852
+ opacity: changeRequestType === 'old' ? 0.95 : 1, // Slight opacity reduction for old sections
3818
3853
  ...(isEditMode && sectionHeight ? {
3819
3854
  height: `${sectionHeight}px`,
3820
3855
  minHeight: `${sectionHeight}px`
@@ -3823,7 +3858,27 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
3823
3858
  minHeight: 'auto',
3824
3859
  height: 'auto'
3825
3860
  }),
3826
- }, children: [sectionToRender['section-title'] && (jsxRuntimeExports.jsx("h2", { className: "text-xl font-semibold mb-4", style: { marginTop: '35px' }, children: translateConfig(sectionToRender['section-title']) })), jsxRuntimeExports.jsxs("div", { id: gridId, className: "section-panels", style: mode === 'RegistryView' && hideEditButton ? { paddingBottom: '40px' } : {}, 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: "border-gray-300 w-full", style: { height: '1px', marginTop: '20px', marginBottom: '0px' } }), jsxRuntimeExports.jsxs("div", { className: "cr-view-container", style: {
3861
+ }, children: [sectionToRender['section-title'] && (jsxRuntimeExports.jsxs("div", { style: {
3862
+ marginTop: '35px',
3863
+ marginBottom: '16px',
3864
+ display: 'flex',
3865
+ alignItems: 'center',
3866
+ gap: '12px',
3867
+ flexWrap: 'wrap',
3868
+ }, children: [jsxRuntimeExports.jsx("h2", { className: "text-xl font-semibold", style: { margin: 0 }, children: translateConfig(sectionToRender['section-title']) }), mode === 'CRView' && changeRequestType && showChangeRequestLabel && (jsxRuntimeExports.jsx("span", { style: {
3869
+ display: 'inline-flex',
3870
+ alignItems: 'center',
3871
+ padding: '4px 12px',
3872
+ borderRadius: '4px',
3873
+ fontSize: '12px',
3874
+ fontWeight: 600,
3875
+ textTransform: 'uppercase',
3876
+ letterSpacing: '0.5px',
3877
+ backgroundColor: changeRequestType === 'new' ? '#28a745' : '#ffcccc', // Green for new, faded red for old
3878
+ color: changeRequestType === 'new' ? '#FFFFFF' : '#cc0000',
3879
+ whiteSpace: 'nowrap',
3880
+ boxShadow: changeRequestType === 'new' ? '0 2px 4px rgba(40, 167, 69, 0.3)' : 'none',
3881
+ }, children: changeRequestType === 'new' ? 'New' : 'Old' }))] })), jsxRuntimeExports.jsxs("div", { id: gridId, className: "section-panels", style: mode === 'RegistryView' && hideEditButton ? { paddingBottom: '40px' } : {}, 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: "border-gray-300 w-full", style: { height: '1px', marginTop: '20px', marginBottom: '0px' } }), jsxRuntimeExports.jsxs("div", { className: "cr-view-container", style: {
3827
3882
  marginTop: '20px',
3828
3883
  paddingBottom: '30px',
3829
3884
  display: 'flex',
@@ -4116,7 +4171,7 @@ if (typeof document !== 'undefined') {
4116
4171
  /**
4117
4172
  * JSON Editor Panel - Left side of Section Builder
4118
4173
  */
4119
- const JSONEditorPanel = ({ section, onChange, onReset, onSelectNode, context = 'section', }) => {
4174
+ const JSONEditorPanel = ({ section, onChange, onReset, context = 'section', }) => {
4120
4175
  const [jsonData, setJsonData] = useState(section);
4121
4176
  const [validationErrors, setValidationErrors] = useState([]);
4122
4177
  const [rawJsonView, setRawJsonView] = useState(false);
@@ -4188,96 +4243,6 @@ const JSONEditorPanel = ({ section, onChange, onReset, onSelectNode, context = '
4188
4243
  window.addEventListener('keydown', handleEscape);
4189
4244
  return () => window.removeEventListener('keydown', handleEscape);
4190
4245
  }, [showPreview]);
4191
- // Handle clicks in JSON editor to select corresponding node in visual builder
4192
- useEffect(() => {
4193
- if (!onSelectNode || rawJsonView)
4194
- return; // Only work in tree view, not raw JSON view
4195
- const handleJsonEditorClick = (e) => {
4196
- const mouseEvent = e;
4197
- const target = mouseEvent.target;
4198
- // Find the key text element (json-edit-react uses .jer-key-text class)
4199
- const keyElement = target.closest('.jer-key-text') ||
4200
- target.querySelector('.jer-key-text') ||
4201
- (target.classList.contains('jer-key-text') ? target : null);
4202
- if (!keyElement)
4203
- return;
4204
- const keyText = keyElement.textContent?.trim();
4205
- if (!keyText)
4206
- return;
4207
- // Remove colon if present
4208
- const keyName = keyText.replace(':', '').trim();
4209
- // Map key names to node types and find the corresponding node
4210
- let nodeId = null;
4211
- let nodeType = null;
4212
- if (keyName === 'section-id') {
4213
- // Find the section-id value
4214
- const keyRow = keyElement.closest('.jer-collection-header-row, .jer-value-row');
4215
- if (keyRow) {
4216
- const valueElement = keyRow.querySelector('.jer-value-text, .jer-string-value');
4217
- if (valueElement) {
4218
- nodeId = valueElement.textContent?.replace(/^"|"$/g, '').trim() || section['section-id'];
4219
- nodeType = 'section';
4220
- }
4221
- }
4222
- }
4223
- else if (keyName === 'panel-id') {
4224
- // Find the panel-id value in the current panel object
4225
- const panelContainer = keyElement.closest('.jer-collection-component');
4226
- if (panelContainer) {
4227
- const valueElement = panelContainer.querySelector('.jer-value-text, .jer-string-value');
4228
- if (valueElement) {
4229
- // Try to find panel-id value in this panel
4230
- const allKeys = panelContainer.querySelectorAll('.jer-key-text');
4231
- for (const key of Array.from(allKeys)) {
4232
- if (key.textContent?.includes('panel-id')) {
4233
- const keyRow = key.closest('.jer-collection-header-row, .jer-value-row');
4234
- if (keyRow) {
4235
- const valElement = keyRow.querySelector('.jer-value-text, .jer-string-value');
4236
- if (valElement) {
4237
- nodeId = valElement.textContent?.replace(/^"|"$/g, '').trim() || null;
4238
- nodeType = 'panel';
4239
- break;
4240
- }
4241
- }
4242
- }
4243
- }
4244
- }
4245
- }
4246
- }
4247
- else if (keyName === 'widget-id') {
4248
- // Find the widget-id value in the current widget object
4249
- const widgetContainer = keyElement.closest('.jer-collection-component');
4250
- if (widgetContainer) {
4251
- const allKeys = widgetContainer.querySelectorAll('.jer-key-text');
4252
- for (const key of Array.from(allKeys)) {
4253
- if (key.textContent?.includes('widget-id')) {
4254
- const keyRow = key.closest('.jer-collection-header-row, .jer-value-row');
4255
- if (keyRow) {
4256
- const valElement = keyRow.querySelector('.jer-value-text, .jer-string-value');
4257
- if (valElement) {
4258
- nodeId = valElement.textContent?.replace(/^"|"$/g, '').trim() || null;
4259
- nodeType = 'widget';
4260
- break;
4261
- }
4262
- }
4263
- }
4264
- }
4265
- }
4266
- }
4267
- // If we found a node, select it in the visual builder
4268
- if (nodeId && nodeType) {
4269
- onSelectNode(nodeId, nodeType);
4270
- }
4271
- };
4272
- // Add click listener to the JSON editor container
4273
- const editorContainer = document.querySelector('.json-editor-scroll-container');
4274
- if (editorContainer) {
4275
- editorContainer.addEventListener('click', handleJsonEditorClick);
4276
- return () => {
4277
- editorContainer.removeEventListener('click', handleJsonEditorClick);
4278
- };
4279
- }
4280
- }, [onSelectNode, rawJsonView, section]);
4281
4246
  // Make section editable for preview - remove readonly flags from widgets
4282
4247
  const makeSectionEditable = useCallback((section) => {
4283
4248
  const processWidget = (widget) => {
@@ -4522,7 +4487,7 @@ const JSONEditorPanel = ({ section, onChange, onReset, onSelectNode, context = '
4522
4487
  minHeight: 0,
4523
4488
  borderRight: '0px',
4524
4489
  }, children: [jsxRuntimeExports.jsxs("div", { style: {
4525
- padding: '15px 20px',
4490
+ padding: '16px 20px',
4526
4491
  background: '#ffffff',
4527
4492
  display: 'flex',
4528
4493
  justifyContent: 'space-between',
@@ -4544,8 +4509,8 @@ const JSONEditorPanel = ({ section, onChange, onReset, onSelectNode, context = '
4544
4509
  }, children: [jsxRuntimeExports.jsxs("button", { onClick: handleReset, style: {
4545
4510
  padding: '6px 12px',
4546
4511
  border: '1px solid #ddd',
4547
- borderRadius: '4px',
4548
- background: 'white',
4512
+ borderRadius: '10px',
4513
+ background: '#f3f3f3',
4549
4514
  color: '#666',
4550
4515
  cursor: 'pointer',
4551
4516
  display: 'flex',
@@ -4563,8 +4528,8 @@ const JSONEditorPanel = ({ section, onChange, onReset, onSelectNode, context = '
4563
4528
  }, title: "Reset to original JSON", children: [jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }), jsxRuntimeExports.jsx("path", { d: "M21 3v5h-5" }), jsxRuntimeExports.jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }), jsxRuntimeExports.jsx("path", { d: "M3 21v-5h5" })] }), "Reset"] }), jsxRuntimeExports.jsxs("button", { onClick: () => setShowPreview(true), style: {
4564
4529
  padding: '6px 12px',
4565
4530
  border: '1px solid #ddd',
4566
- borderRadius: '4px',
4567
- background: 'white',
4531
+ borderRadius: '10px',
4532
+ background: '#f3f3f3',
4568
4533
  color: '#666',
4569
4534
  cursor: 'pointer',
4570
4535
  display: 'flex',
@@ -4920,18 +4885,24 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
4920
4885
  border: '1px solid #ccc',
4921
4886
  borderRadius: '4px',
4922
4887
  fontSize: '12px',
4888
+ background: 'white',
4889
+ color: '#333',
4923
4890
  } })] }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '12px', fontWeight: 500 }, children: "Section Title" }), jsxRuntimeExports.jsx("input", { type: "text", value: section['section-title'] || '', onChange: (e) => handleChange('section-title', e.target.value), style: {
4924
4891
  width: '100%',
4925
4892
  padding: '8px 12px',
4926
4893
  border: '1px solid #ccc',
4927
4894
  borderRadius: '4px',
4928
4895
  fontSize: '12px',
4896
+ background: 'white',
4897
+ color: '#333',
4929
4898
  } })] }), jsxRuntimeExports.jsx("div", { style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '12px' }, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: section['section-editable'] || false, onChange: (e) => handleChange('section-editable', e.target.checked) }), jsxRuntimeExports.jsx("span", { children: "Editable" })] }) }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '12px', fontWeight: 500 }, children: "Column Span" }), jsxRuntimeExports.jsx("input", { type: "number", value: section['section-column-span'] || 1, onChange: (e) => handleChange('section-column-span', parseInt(e.target.value) || 1), min: "1", style: {
4930
4899
  width: '100%',
4931
4900
  padding: '8px 12px',
4932
4901
  border: '1px solid #ccc',
4933
4902
  borderRadius: '4px',
4934
4903
  fontSize: '12px',
4904
+ background: 'white',
4905
+ color: '#333',
4935
4906
  } })] })] }));
4936
4907
  };
4937
4908
  const renderPanelProperties = () => {
@@ -4942,6 +4913,8 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
4942
4913
  border: '1px solid #ccc',
4943
4914
  borderRadius: '4px',
4944
4915
  fontSize: '12px',
4916
+ background: 'white',
4917
+ color: '#333',
4945
4918
  } })] }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '12px', fontWeight: 500 }, children: "Orientation" }), jsxRuntimeExports.jsx("select", { value: panel['panel-orientation'] || 'vertical', onChange: (e) => handleChange('panel-orientation', e.target.value), style: {
4946
4919
  width: '100%',
4947
4920
  padding: '8px 12px',
@@ -4955,6 +4928,8 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
4955
4928
  border: '1px solid #ccc',
4956
4929
  borderRadius: '4px',
4957
4930
  fontSize: '12px',
4931
+ background: 'white',
4932
+ color: '#333',
4958
4933
  } })] })] }));
4959
4934
  };
4960
4935
  const renderWidgetProperties = () => {
@@ -4988,24 +4963,32 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
4988
4963
  border: '1px solid #ccc',
4989
4964
  borderRadius: '4px',
4990
4965
  fontSize: '12px',
4966
+ background: 'white',
4967
+ color: '#333',
4991
4968
  } })] }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '12px', fontWeight: 500 }, children: "Widget Label" }), jsxRuntimeExports.jsx("input", { type: "text", value: widget['widget-label'] || '', onChange: (e) => handleChange('widget-label', e.target.value), style: {
4992
4969
  width: '100%',
4993
4970
  padding: '8px 12px',
4994
4971
  border: '1px solid #ccc',
4995
4972
  borderRadius: '4px',
4996
4973
  fontSize: '12px',
4974
+ background: 'white',
4975
+ color: '#333',
4997
4976
  }, placeholder: "Enter label..." })] }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '12px', fontWeight: 500 }, children: "Data Path" }), jsxRuntimeExports.jsx("input", { type: "text", value: typeof widget['widget-data-path'] === 'string' ? widget['widget-data-path'] : '', onChange: (e) => handleChange('widget-data-path', e.target.value), style: {
4998
4977
  width: '100%',
4999
4978
  padding: '8px 12px',
5000
4979
  border: '1px solid #ccc',
5001
4980
  borderRadius: '4px',
5002
4981
  fontSize: '12px',
4982
+ background: 'white',
4983
+ color: '#333',
5003
4984
  }, placeholder: "person.name" })] }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '12px', fontWeight: 500 }, children: "Placeholder" }), jsxRuntimeExports.jsx("input", { type: "text", value: widget['widget-data-placeholder'] || '', onChange: (e) => handleChange('widget-data-placeholder', e.target.value), style: {
5004
4985
  width: '100%',
5005
4986
  padding: '8px 12px',
5006
4987
  border: '1px solid #ccc',
5007
4988
  borderRadius: '4px',
5008
4989
  fontSize: '12px',
4990
+ background: 'white',
4991
+ color: '#333',
5009
4992
  }, placeholder: "Enter placeholder..." })] }), jsxRuntimeExports.jsx("div", { style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '12px' }, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: widget['widget-required'] || false, onChange: (e) => handleChange('widget-required', e.target.checked) }), jsxRuntimeExports.jsx("span", { children: "Required" })] }) }), jsxRuntimeExports.jsx("div", { style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '12px' }, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: widget['widget-readonly'] || false, onChange: (e) => handleChange('widget-readonly', e.target.checked) }), jsxRuntimeExports.jsx("span", { children: "Readonly" })] }) }), ['select', 'radio', 'checkbox'].includes(widget.widget) && (jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px', padding: '10px', background: '#e3f2fd', borderRadius: '4px' }, children: [jsxRuntimeExports.jsxs("label", { style: { display: 'block', marginBottom: '8px', fontSize: '12px', fontWeight: 600 }, children: ["Data Source (Required for ", widget.widget, ")"] }), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '10px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Source Type" }), jsxRuntimeExports.jsxs("select", { value: widget['widget-data-source']?.type || 'static', onChange: (e) => {
5010
4993
  ensureNestedObject('widget-data-source');
5011
4994
  handleNestedChange('widget-data-source', 'type', e.target.value);
@@ -5032,6 +5015,8 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5032
5015
  fontSize: '11px',
5033
5016
  fontFamily: 'monospace',
5034
5017
  minHeight: '80px',
5018
+ background: 'white',
5019
+ color: '#333',
5035
5020
  }, placeholder: '[{"value": "opt1", "label": "Option 1"}]' })] })), widget['widget-data-source']?.type === 'api' && (() => {
5036
5021
  const apiSource = widget['widget-data-source'];
5037
5022
  return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { style: { marginBottom: '10px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "API URL" }), jsxRuntimeExports.jsx("input", { type: "text", value: apiSource.url || '', onChange: (e) => handleNestedChange('widget-data-source', 'url', e.target.value), style: {
@@ -5040,18 +5025,24 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5040
5025
  border: '1px solid #ccc',
5041
5026
  borderRadius: '4px',
5042
5027
  fontSize: '11px',
5028
+ background: 'white',
5029
+ color: '#333',
5043
5030
  }, placeholder: "https://api.example.com/options" })] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Value/Label Keys (e.g., \"id\"/\"name\")" }), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [jsxRuntimeExports.jsx("input", { type: "text", value: apiSource.valueKey || '', onChange: (e) => handleNestedChange('widget-data-source', 'valueKey', e.target.value), style: {
5044
5031
  flex: 1,
5045
5032
  padding: '6px 8px',
5046
5033
  border: '1px solid #ccc',
5047
5034
  borderRadius: '4px',
5048
5035
  fontSize: '11px',
5036
+ background: 'white',
5037
+ color: '#333',
5049
5038
  }, placeholder: "value key" }), jsxRuntimeExports.jsx("input", { type: "text", value: apiSource.labelKey || '', onChange: (e) => handleNestedChange('widget-data-source', 'labelKey', e.target.value), style: {
5050
5039
  flex: 1,
5051
5040
  padding: '6px 8px',
5052
5041
  border: '1px solid #ccc',
5053
5042
  borderRadius: '4px',
5054
5043
  fontSize: '11px',
5044
+ background: 'white',
5045
+ color: '#333',
5055
5046
  }, placeholder: "label key" })] })] })] }));
5056
5047
  })()] })), widget.widget === 'table' && (jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px', padding: '10px', background: '#fff3e0', borderRadius: '4px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '8px', fontSize: '12px', fontWeight: 600 }, children: "Table Columns" }), jsxRuntimeExports.jsx("div", { style: { fontSize: '11px', color: '#666', marginBottom: '10px' }, children: "Configure columns in JSON editor or add via code" }), jsxRuntimeExports.jsx("textarea", { value: JSON.stringify(widget['widget-data-columns'] || [], null, 2), onChange: (e) => {
5057
5048
  try {
@@ -5069,30 +5060,40 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5069
5060
  fontSize: '11px',
5070
5061
  fontFamily: 'monospace',
5071
5062
  minHeight: '100px',
5063
+ background: 'white',
5064
+ color: '#333',
5072
5065
  }, placeholder: '[{"column-key": "col1", "widget-label": "Column 1", "widget": "text"}]' })] })), widget.widget === 'number' && (jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px', padding: '10px', background: '#f3e5f5', borderRadius: '4px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '8px', fontSize: '12px', fontWeight: 600 }, children: "Number Validation" }), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: '10px', marginBottom: '10px' }, children: [jsxRuntimeExports.jsxs("div", { style: { flex: 1 }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Min Value" }), jsxRuntimeExports.jsx("input", { type: "number", value: widget['widget-data-validation']?.min ?? '', onChange: (e) => handleNestedChange('widget-data-validation', 'min', e.target.value ? parseFloat(e.target.value) : undefined), style: {
5073
5066
  width: '100%',
5074
5067
  padding: '6px 8px',
5075
5068
  border: '1px solid #ccc',
5076
5069
  borderRadius: '4px',
5077
5070
  fontSize: '11px',
5071
+ background: 'white',
5072
+ color: '#333',
5078
5073
  } })] }), jsxRuntimeExports.jsxs("div", { style: { flex: 1 }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Max Value" }), jsxRuntimeExports.jsx("input", { type: "number", value: widget['widget-data-validation']?.max ?? '', onChange: (e) => handleNestedChange('widget-data-validation', 'max', e.target.value ? parseFloat(e.target.value) : undefined), style: {
5079
5074
  width: '100%',
5080
5075
  padding: '6px 8px',
5081
5076
  border: '1px solid #ccc',
5082
5077
  borderRadius: '4px',
5083
5078
  fontSize: '11px',
5079
+ background: 'white',
5080
+ color: '#333',
5084
5081
  } })] })] })] })), ['date', 'datetime'].includes(widget.widget) && (jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px', padding: '10px', background: '#e8f5e9', borderRadius: '4px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '8px', fontSize: '12px', fontWeight: 600 }, children: "Date Range Options" }), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: '10px', marginBottom: '10px' }, children: [jsxRuntimeExports.jsxs("div", { style: { flex: 1 }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Min Date" }), jsxRuntimeExports.jsx("input", { type: "date", value: widget['widget-data-options']?.minDate || '', onChange: (e) => handleNestedChange('widget-data-options', 'minDate', e.target.value || undefined), style: {
5085
5082
  width: '100%',
5086
5083
  padding: '6px 8px',
5087
5084
  border: '1px solid #ccc',
5088
5085
  borderRadius: '4px',
5089
5086
  fontSize: '11px',
5087
+ background: 'white',
5088
+ color: '#333',
5090
5089
  } })] }), jsxRuntimeExports.jsxs("div", { style: { flex: 1 }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Max Date" }), jsxRuntimeExports.jsx("input", { type: "date", value: widget['widget-data-options']?.maxDate || '', onChange: (e) => handleNestedChange('widget-data-options', 'maxDate', e.target.value || undefined), style: {
5091
5090
  width: '100%',
5092
5091
  padding: '6px 8px',
5093
5092
  border: '1px solid #ccc',
5094
5093
  borderRadius: '4px',
5095
5094
  fontSize: '11px',
5095
+ background: 'white',
5096
+ color: '#333',
5096
5097
  } })] })] }), jsxRuntimeExports.jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '11px' }, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: widget['widget-data-options']?.showCalendar || false, onChange: (e) => handleNestedChange('widget-data-options', 'showCalendar', e.target.checked) }), jsxRuntimeExports.jsx("span", { children: "Show Calendar" })] })] })), jsxRuntimeExports.jsxs("div", { style: { marginBottom: '20px', padding: '10px', background: '#f0f0f0', borderRadius: '4px' }, children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '8px', fontSize: '12px', fontWeight: 600 }, children: "Validation" }), jsxRuntimeExports.jsx("div", { style: { marginBottom: '10px' }, children: jsxRuntimeExports.jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '12px' }, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: widget['widget-data-validation']?.required || false, onChange: (e) => {
5097
5098
  if (!widget['widget-data-validation']) {
5098
5099
  handleChange('widget-data-validation', { required: e.target.checked });
@@ -5112,6 +5113,8 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5112
5113
  border: '1px solid #ccc',
5113
5114
  borderRadius: '4px',
5114
5115
  fontSize: '11px',
5116
+ background: 'white',
5117
+ color: '#333',
5115
5118
  } })] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("label", { style: { display: 'block', marginBottom: '5px', fontSize: '11px' }, children: "Max Length" }), jsxRuntimeExports.jsx("input", { type: "number", value: widget['widget-data-validation']?.maxLength || '', onChange: (e) => {
5116
5119
  const validation = widget['widget-data-validation'] || {};
5117
5120
  handleChange('widget-data-validation', {
@@ -5124,6 +5127,8 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5124
5127
  border: '1px solid #ccc',
5125
5128
  borderRadius: '4px',
5126
5129
  fontSize: '11px',
5130
+ background: 'white',
5131
+ color: '#333',
5127
5132
  } })] })] }))] })] }));
5128
5133
  };
5129
5134
  const getHeaderColor = () => {
@@ -5153,7 +5158,7 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5153
5158
  flex: 1,
5154
5159
  padding: '10px',
5155
5160
  border: 'none',
5156
- borderRadius: '4px',
5161
+ borderRadius: '10px',
5157
5162
  background: '#f44336',
5158
5163
  color: 'white',
5159
5164
  fontWeight: 600,
@@ -5163,7 +5168,7 @@ const PropertyEditor = ({ node, onChange, onDelete, onDuplicate, }) => {
5163
5168
  flex: 1,
5164
5169
  padding: '10px',
5165
5170
  border: 'none',
5166
- borderRadius: '4px',
5171
+ borderRadius: '10px',
5167
5172
  background: '#ff9800',
5168
5173
  color: 'white',
5169
5174
  fontWeight: 600,
@@ -5322,17 +5327,18 @@ const VisualBuilderPanel = ({ section, selectedNode, onSelectNode, onSectionChan
5322
5327
  height: '100%',
5323
5328
  width: '100%',
5324
5329
  minHeight: 0,
5330
+ paddingBottom: '10px',
5331
+ borderRight: '0px',
5325
5332
  }, children: [jsxRuntimeExports.jsxs("div", { style: {
5326
- padding: '15px 20px',
5333
+ padding: '20px 20px 20px 20px',
5327
5334
  background: '#ffffff',
5328
- borderBottom: '1px solid #ddd',
5329
5335
  display: 'flex',
5330
5336
  justifyContent: 'space-between',
5331
5337
  alignItems: 'center',
5332
- }, children: [jsxRuntimeExports.jsx("div", { style: { fontWeight: 600, fontSize: '16px', color: '#2c3e50' }, children: "Visual Builder" }), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: '10px' }, children: [jsxRuntimeExports.jsx("button", { onClick: handleAddPanel, style: {
5338
+ }, children: [jsxRuntimeExports.jsx("div", { style: { fontWeight: 600, fontSize: '16px', color: '#2c3e50', paddingTop: '5px' }, children: "Visual Builder" }), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: '10px' }, children: [jsxRuntimeExports.jsx("button", { onClick: handleAddPanel, style: {
5333
5339
  padding: '8px 16px',
5334
5340
  border: 'none',
5335
- borderRadius: '4px',
5341
+ borderRadius: '10px',
5336
5342
  background: '#2196f3',
5337
5343
  color: 'white',
5338
5344
  fontWeight: 600,
@@ -5342,7 +5348,7 @@ const VisualBuilderPanel = ({ section, selectedNode, onSelectNode, onSectionChan
5342
5348
  }, children: "+ Add Panel" }), jsxRuntimeExports.jsx("button", { onClick: handleAddWidget, style: {
5343
5349
  padding: '8px 16px',
5344
5350
  border: 'none',
5345
- borderRadius: '4px',
5351
+ borderRadius: '10px',
5346
5352
  background: '#4caf50',
5347
5353
  color: 'white',
5348
5354
  fontWeight: 600,
@@ -5352,8 +5358,8 @@ const VisualBuilderPanel = ({ section, selectedNode, onSelectNode, onSectionChan
5352
5358
  }, children: "+ Add Widget" }), onSave && (jsxRuntimeExports.jsx("button", { onClick: handleSave, style: {
5353
5359
  padding: '8px 16px',
5354
5360
  border: 'none',
5355
- borderRadius: '4px',
5356
- background: '#ff9800',
5361
+ borderRadius: '10px',
5362
+ background: '#000000',
5357
5363
  color: 'white',
5358
5364
  fontWeight: 600,
5359
5365
  cursor: 'pointer',
@@ -5375,6 +5381,8 @@ const VisualBuilderPanel = ({ section, selectedNode, onSelectNode, onSectionChan
5375
5381
  flex: 1,
5376
5382
  display: 'flex',
5377
5383
  overflow: 'hidden',
5384
+ border: '1px solid #ddd',
5385
+ borderRadius: '10px',
5378
5386
  minHeight: 0, // Important for flex children to respect overflow
5379
5387
  }, children: [jsxRuntimeExports.jsx("div", { style: {
5380
5388
  width: '45%',
@@ -5434,77 +5442,6 @@ const SectionBuilder = ({ initialSection, onChange, onSave, }) => {
5434
5442
  onChange(original);
5435
5443
  }
5436
5444
  }, [onChange]);
5437
- // Handle node selection from JSON editor
5438
- const handleSelectNodeFromJson = useCallback((nodeId, nodeType) => {
5439
- // Find the corresponding node in the section structure
5440
- const findNode = () => {
5441
- if (nodeType === 'section') {
5442
- return {
5443
- type: 'section',
5444
- id: section['section-id'],
5445
- label: `Section: ${section['section-id']}`,
5446
- data: section,
5447
- };
5448
- }
5449
- // Recursively search for panel or widget
5450
- const searchInPanels = (panels, parent) => {
5451
- for (const panel of panels) {
5452
- if (nodeType === 'panel' && panel['panel-id'] === nodeId) {
5453
- return {
5454
- type: 'panel',
5455
- id: panel['panel-id'],
5456
- label: `Panel: ${panel['panel-id']}`,
5457
- data: panel,
5458
- parent: parent,
5459
- };
5460
- }
5461
- // Check nested panels
5462
- if (panel.panels) {
5463
- const panelNode = {
5464
- type: 'panel',
5465
- id: panel['panel-id'],
5466
- label: `Panel: ${panel['panel-id']}`,
5467
- data: panel,
5468
- parent: parent,
5469
- };
5470
- const found = searchInPanels(panel.panels, panelNode);
5471
- if (found)
5472
- return found;
5473
- }
5474
- // Check widgets
5475
- if (panel.widgets) {
5476
- const panelNode = {
5477
- type: 'panel',
5478
- id: panel['panel-id'],
5479
- label: `Panel: ${panel['panel-id']}`,
5480
- data: panel,
5481
- parent: parent,
5482
- };
5483
- for (const widget of panel.widgets) {
5484
- if (nodeType === 'widget' && widget['widget-id'] === nodeId) {
5485
- return {
5486
- type: 'widget',
5487
- id: widget['widget-id'],
5488
- label: `Widget: ${widget['widget-id']} (${widget.widget})`,
5489
- data: widget,
5490
- parent: panelNode,
5491
- };
5492
- }
5493
- }
5494
- }
5495
- }
5496
- return null;
5497
- };
5498
- if (section.panels) {
5499
- return searchInPanels(section.panels);
5500
- }
5501
- return null;
5502
- };
5503
- const node = findNode();
5504
- if (node) {
5505
- setSelectedNode(node);
5506
- }
5507
- }, [section]);
5508
5445
  const handleAddPanel = useCallback((parentId, parentType) => {
5509
5446
  const updatedSection = JSON.parse(JSON.stringify(section));
5510
5447
  const newPanel = {
@@ -5684,7 +5621,7 @@ const SectionBuilder = ({ initialSection, onChange, onSave, }) => {
5684
5621
  padding: '10px 10px 10px 10px',
5685
5622
  flexDirection: 'column',
5686
5623
  borderRight: '0px',
5687
- }, children: jsxRuntimeExports.jsx(JSONEditorPanel, { section: section, onChange: handleSectionChange, onReset: handleReset, onSelectNode: handleSelectNodeFromJson }) }), jsxRuntimeExports.jsx("div", { style: {
5624
+ }, children: jsxRuntimeExports.jsx(JSONEditorPanel, { section: section, onChange: handleSectionChange, onReset: handleReset }) }), jsxRuntimeExports.jsx("div", { style: {
5688
5625
  width: '50%',
5689
5626
  height: '100%',
5690
5627
  minHeight: 0,
@@ -7514,8 +7451,41 @@ const CurrencyInputWidget = ({ config }) => {
7514
7451
  const DisplayWidget = ({ config }) => {
7515
7452
  const { value, formattedValue, config: widgetConfig, } = useBaseWidget({ config });
7516
7453
  const { translateConfig } = useWidgetTranslation();
7517
- // Use formatted value if available, otherwise raw value
7518
- const displayValue = formattedValue !== undefined ? formattedValue : (value || '');
7454
+ // Helper to safely convert value to display string
7455
+ const getDisplayValue = (val) => {
7456
+ if (val === null || val === undefined) {
7457
+ return '';
7458
+ }
7459
+ // If it's already a string or number, return as string
7460
+ if (typeof val === 'string' || typeof val === 'number') {
7461
+ return String(val);
7462
+ }
7463
+ // If it's an object (like geo hierarchy), try to extract a meaningful value
7464
+ if (typeof val === 'object' && !Array.isArray(val)) {
7465
+ // For geo hierarchy objects, try to extract the actual value
7466
+ if ('geo_lowest_level_value_id' in val) {
7467
+ return String(val.geo_lowest_level_value_id || '');
7468
+ }
7469
+ if ('value' in val) {
7470
+ return String(val.value || '');
7471
+ }
7472
+ if ('id' in val) {
7473
+ return String(val.id || '');
7474
+ }
7475
+ // If no extractable value, return empty string to avoid rendering object
7476
+ return '';
7477
+ }
7478
+ // For arrays, join them or return empty
7479
+ if (Array.isArray(val)) {
7480
+ return val.length > 0 ? val.map(String).join(', ') : '';
7481
+ }
7482
+ // Fallback: convert to string
7483
+ return String(val);
7484
+ };
7485
+ // Use formatted value if available, otherwise safely convert raw value
7486
+ const displayValue = formattedValue !== undefined
7487
+ ? (typeof formattedValue === 'object' ? getDisplayValue(formattedValue) : String(formattedValue))
7488
+ : getDisplayValue(value);
7519
7489
  const label = translateConfig(widgetConfig['widget-label']);
7520
7490
  // If no label, render as paragraph text
7521
7491
  if (!label || label.trim() === '') {