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