@adaptabletools/adaptable 23.0.0-canary.7 → 23.0.0-canary.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/index.css +75 -9
  2. package/package.json +1 -1
  3. package/src/AdaptableState/StyledColumnState.d.ts +8 -850
  4. package/src/AdaptableState/StyledColumnState.js +1 -9
  5. package/src/AdaptableState/StyledColumns/BadgeStyle.d.ts +143 -0
  6. package/src/AdaptableState/StyledColumns/BadgeStyle.js +9 -0
  7. package/src/AdaptableState/StyledColumns/BulletChartStyle.d.ts +147 -0
  8. package/src/AdaptableState/StyledColumns/BulletChartStyle.js +1 -0
  9. package/src/AdaptableState/StyledColumns/Common/BarChartCellText.d.ts +60 -0
  10. package/src/AdaptableState/StyledColumns/Common/BarChartCellText.js +6 -0
  11. package/src/AdaptableState/StyledColumns/Common/BarChartMarker.d.ts +24 -0
  12. package/src/AdaptableState/StyledColumns/Common/BarChartMarker.js +5 -0
  13. package/src/AdaptableState/StyledColumns/Common/CellTextOptions.d.ts +13 -0
  14. package/src/AdaptableState/StyledColumns/Common/CellTextOptions.js +6 -0
  15. package/src/AdaptableState/StyledColumns/Common/NumericStyledColumn.d.ts +79 -0
  16. package/src/AdaptableState/StyledColumns/Common/NumericStyledColumn.js +9 -0
  17. package/src/AdaptableState/StyledColumns/GradientStyle.d.ts +48 -0
  18. package/src/AdaptableState/StyledColumns/GradientStyle.js +1 -0
  19. package/src/AdaptableState/StyledColumns/IconStyle.d.ts +158 -0
  20. package/src/AdaptableState/StyledColumns/IconStyle.js +1 -0
  21. package/src/AdaptableState/StyledColumns/PercentBarStyle.d.ts +32 -0
  22. package/src/AdaptableState/StyledColumns/PercentBarStyle.js +1 -0
  23. package/src/AdaptableState/StyledColumns/RangeBarStyle.d.ts +155 -0
  24. package/src/AdaptableState/StyledColumns/RangeBarStyle.js +1 -0
  25. package/src/AdaptableState/StyledColumns/RatingStyle.d.ts +111 -0
  26. package/src/AdaptableState/StyledColumns/RatingStyle.js +1 -0
  27. package/src/AdaptableState/StyledColumns/SparklineStyle.d.ts +21 -0
  28. package/src/AdaptableState/StyledColumns/SparklineStyle.js +1 -0
  29. package/src/Api/ColumnScopeApi.d.ts +1 -1
  30. package/src/Api/Implementation/ColumnScopeApiImpl.d.ts +1 -1
  31. package/src/Api/Internal/StyledColumnInternalApi.d.ts +3 -1
  32. package/src/Utilities/Helpers/IconStylePresets.d.ts +1 -1
  33. package/src/Utilities/Helpers/StyledColumnGradientHelper.d.ts +3 -1
  34. package/src/Utilities/Helpers/barChartCellText.d.ts +63 -0
  35. package/src/Utilities/Helpers/barChartCellText.js +316 -0
  36. package/src/Utilities/Helpers/percentBarPreviewHelper.d.ts +2 -1
  37. package/src/Utilities/Helpers/percentBarPreviewHelper.js +3 -8
  38. package/src/View/Alert/Wizard/AlertButtonsEditor.js +159 -126
  39. package/src/View/Alert/Wizard/AlertNotificationWizardSection.js +1 -1
  40. package/src/View/Alert/Wizard/AlertWizard.js +9 -1
  41. package/src/View/Components/AdaptableObjectList/AdaptableObjectCompactList.js +3 -2
  42. package/src/View/Components/AdaptableObjectList/AdaptableObjectList.js +3 -2
  43. package/src/View/Components/AdaptableObjectList/objectListActionButtonStyles.d.ts +2 -0
  44. package/src/View/Components/AdaptableObjectList/objectListActionButtonStyles.js +2 -0
  45. package/src/View/Components/Buttons/EntityListActionButtons.js +1 -1
  46. package/src/View/Components/Buttons/SuspendToggleButton/SuspendToggleButton.d.ts +1 -0
  47. package/src/View/Components/Buttons/SuspendToggleButton/SuspendToggleButton.js +8 -8
  48. package/src/View/Components/ColumnFilter/ColumnFilter.js +14 -1
  49. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopupModuleView.js +1 -1
  50. package/src/View/Components/RangesComponent.d.ts +2 -1
  51. package/src/View/Export/ExportSchedulesTab.js +3 -4
  52. package/src/View/Filter/FilterViewPanel.js +1 -1
  53. package/src/View/Layout/Wizard/sections/RowSummarySection.js +129 -103
  54. package/src/View/StyledColumn/Wizard/BadgePillStyleEditor.d.ts +1 -1
  55. package/src/View/StyledColumn/Wizard/StyledColumnBadgeSection.js +36 -30
  56. package/src/View/StyledColumn/Wizard/StyledColumnSliceStyleEditors.d.ts +1 -3
  57. package/src/View/StyledColumn/Wizard/StyledColumnWizardBulletSection.js +73 -58
  58. package/src/View/StyledColumn/Wizard/StyledColumnWizardIconSection.js +38 -11
  59. package/src/View/StyledColumn/Wizard/StyledColumnWizardRangeBarSection.js +86 -44
  60. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/BarChartCellTextLayoutEditor.d.ts +9 -0
  61. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/BarChartCellTextLayoutEditor.js +35 -0
  62. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/BarChartCellTextPreview.d.ts +23 -0
  63. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/BarChartCellTextPreview.js +57 -0
  64. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/BulletRangesSummaryPreview.d.ts +1 -1
  65. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/GradientSummaryPreview.d.ts +2 -1
  66. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/RangeBarRangesSummaryPreview.d.ts +1 -1
  67. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnBadgePreview.js +3 -2
  68. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnBulletPreview.d.ts +2 -1
  69. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnBulletPreview.js +13 -17
  70. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnChartListPreviews.d.ts +2 -1
  71. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnChartListPreviews.js +5 -5
  72. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnIconPreview.js +2 -2
  73. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnPercentBarPreview.js +14 -7
  74. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnRangeBarPreview.js +11 -17
  75. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/Components/StyledColumnRatingPreview.d.ts +2 -1
  76. package/src/View/StyledColumn/Wizard/StyledColumnWizardStyleSection/StyledColumnWizardStyleSection.js +18 -54
  77. package/src/agGrid/AgGridColumnAdapter.js +2 -1
  78. package/src/agGrid/cellRenderers/BadgeRenderer.js +7 -5
  79. package/src/agGrid/cellRenderers/BulletChartRenderer.js +43 -42
  80. package/src/agGrid/cellRenderers/IconRenderer.d.ts +2 -1
  81. package/src/agGrid/cellRenderers/IconRenderer.js +13 -11
  82. package/src/agGrid/cellRenderers/PercentBarRenderer.js +24 -96
  83. package/src/agGrid/cellRenderers/RangeBarRenderer.js +49 -46
  84. package/src/env.js +2 -2
  85. package/src/metamodel/adaptable.metamodel.d.ts +80 -14
  86. package/src/metamodel/adaptable.metamodel.js +1 -1
  87. package/src/migration/VersionUpgrade23.d.ts +27 -31
  88. package/src/migration/VersionUpgrade23.js +110 -29
  89. package/src/types.d.ts +12 -1
  90. package/tsconfig.esm.tsbuildinfo +1 -1
@@ -9,7 +9,6 @@ import { RangesComponent } from '../../Components/RangesComponent';
9
9
  import { ColumnSelector } from '../../Components/Selectors/ColumnSelector';
10
10
  import { getGraySwatchColor } from '../../UIHelper';
11
11
  import { useOnePageAdaptableWizardContext } from '../../Wizard/OnePageAdaptableWizard';
12
- import ArrayExtensions from '../../../Utilities/Extensions/ArrayExtensions';
13
12
  import AdaptableInput from '../../Components/AdaptableInput';
14
13
  import { Box, Flex } from '../../../components/Flex';
15
14
  import { BulletRangesSummaryPreview } from './StyledColumnWizardStyleSection/Components/BulletRangesSummaryPreview';
@@ -18,10 +17,9 @@ import { SingleSelect } from '../../../components/NewSelect';
18
17
  import { getCellFontStyleSummaryItems, StyledColumnFontStyleEditor, } from './StyledColumnSliceStyleEditors';
19
18
  import { Card } from '../../../components/Card';
20
19
  import { renderSummaryStringTags } from '../../Wizard/SummaryColorTag';
20
+ import { formatBarChartCellTextLayoutSummary, getActiveBarChartCellTextTokens, hasBarChartCellTextConfigured, patchBarChartCellTextPlacement, resolveBarChartCellTextLayout, toggleBarChartCellTextToken, } from '../../../Utilities/Helpers/barChartCellText';
21
+ import { BarChartCellTextLayoutEditor } from './StyledColumnWizardStyleSection/Components/BarChartCellTextLayoutEditor';
21
22
  const BULLET_STYLE_FORM_SIZES = ['200px', '1fr'];
22
- // ---------------------------------------------------------------------------
23
- // Summary helpers
24
- // ---------------------------------------------------------------------------
25
23
  const getTargetSummary = (target) => {
26
24
  if (target == undefined) {
27
25
  return null;
@@ -73,11 +71,12 @@ export const getStyledColumnBulletRangesViewValues = (data) => {
73
71
  };
74
72
  const buildStyledColumnBulletStyleSummaryStrings = (bullet, options) => {
75
73
  const items = [];
76
- const targetSummary = getTargetSummary(bullet.Target);
74
+ const targetProperties = bullet.TargetProperties;
75
+ const targetSummary = getTargetSummary(targetProperties?.Target);
77
76
  if (targetSummary) {
78
77
  items.push(`Target: ${targetSummary}`);
79
78
  }
80
- const marker = bullet.TargetMarker;
79
+ const marker = targetProperties?.Marker;
81
80
  if (marker?.Shape && marker.Shape !== 'Line') {
82
81
  items.push(`Target Marker Shape: ${marker.Shape}`);
83
82
  }
@@ -90,19 +89,24 @@ const buildStyledColumnBulletStyleSummaryStrings = (bullet, options) => {
90
89
  if (bullet.Orientation === 'Vertical') {
91
90
  items.push('Orientation: Vertical');
92
91
  }
93
- if (bullet.BarColor) {
94
- items.push(`Bar Colour: ${bullet.BarColor}`);
92
+ const barProperties = bullet.Bar;
93
+ if (barProperties?.Color) {
94
+ items.push(`Bar Colour: ${barProperties.Color}`);
95
95
  }
96
- if (bullet.BarHeight != null) {
97
- items.push(`${bullet.Orientation === 'Vertical' ? 'Bar Width' : 'Bar Height'}: ${bullet.BarHeight}px`);
96
+ if (barProperties?.Height != null) {
97
+ items.push(`${bullet.Orientation === 'Vertical' ? 'Bar Width' : 'Bar Height'}: ${barProperties.Height}px`);
98
98
  }
99
99
  items.push(`Origin: ${formatBulletOriginLabel(bullet.Origin)}`);
100
100
  if (bullet.BackColor) {
101
101
  items.push(`Back Colour: ${bullet.BackColor}`);
102
102
  }
103
- if (bullet.CellText?.length) {
104
- items.push(`Cell Text: ${formatBulletCellTextSummary(bullet.CellText)}`);
105
- items.push(`Cell Text Position: ${bullet.CellTextPosition ?? 'Below'}`);
103
+ if (hasBarChartCellTextConfigured(bullet.CellTextProperties)) {
104
+ const tokens = getActiveBarChartCellTextTokens(bullet.CellTextProperties);
105
+ items.push(`Cell Text: ${formatBulletCellTextSummary(tokens)}`);
106
+ const layoutSummary = formatBarChartCellTextLayoutSummary(resolveBarChartCellTextLayout(bullet.CellTextProperties));
107
+ if (layoutSummary) {
108
+ items.push(`Placement: ${layoutSummary}`);
109
+ }
106
110
  }
107
111
  else if (options.includeEmptyCellText) {
108
112
  items.push('Cell Text: None');
@@ -260,20 +264,28 @@ export const StyledColumnWizardBulletSection = (props) => {
260
264
  });
261
265
  }, [data, bullet]);
262
266
  // -- Target ----------------------------------------------------------------
263
- const currentMode = getSimpleTargetMode(bullet.Target);
267
+ const currentMode = getSimpleTargetMode(bullet.TargetProperties?.Target);
268
+ const updateTargetProperties = (patch) => {
269
+ const merged = {
270
+ ...bullet.TargetProperties,
271
+ ...patch,
272
+ };
273
+ // Strip the wrapper when nothing meaningful is left.
274
+ const isEmpty = merged.Target == undefined && merged.Marker == undefined;
275
+ update({ TargetProperties: isEmpty ? undefined : merged });
276
+ };
277
+ const setTarget = (target) => updateTargetProperties({ Target: target });
264
278
  const handleTargetModeChange = (mode) => {
265
279
  if (mode === 'None') {
266
- const next = { ...bullet };
267
- delete next.Target;
268
- props.onChange({ ...data, BulletChartStyle: next });
280
+ setTarget(undefined);
269
281
  return;
270
282
  }
271
283
  if (mode === 'Col-Avg' || mode === 'Col-Median') {
272
- update({ Target: mode });
284
+ setTarget(mode);
273
285
  return;
274
286
  }
275
287
  if (mode === 'Number') {
276
- update({ Target: minMaxRangeValues?.max ?? 0 });
288
+ setTarget(minMaxRangeValues?.max ?? 0);
277
289
  return;
278
290
  }
279
291
  if (mode === 'Column') {
@@ -281,38 +293,43 @@ export const StyledColumnWizardBulletSection = (props) => {
281
293
  const candidate = api.columnApi
282
294
  .getNumericColumns()
283
295
  .find((c) => c.columnId !== data.ColumnId);
284
- update({ Target: candidate?.columnId ?? '' });
296
+ setTarget(candidate?.columnId ?? '');
285
297
  return;
286
298
  }
287
299
  };
288
300
  const handleNumericTargetChange = (value) => {
289
- if (value == undefined || isNaN(value)) {
290
- update({ Target: 0 });
291
- }
292
- else {
293
- update({ Target: value });
294
- }
301
+ setTarget(value == undefined || isNaN(value) ? 0 : value);
295
302
  };
296
303
  const handleColumnTargetChange = (columnId) => {
297
- update({ Target: columnId });
304
+ setTarget(columnId);
305
+ };
306
+ // -- Bar -------------------------------------------------------------------
307
+ const updateBar = (patch) => {
308
+ const merged = {
309
+ ...bullet.Bar,
310
+ ...patch,
311
+ };
312
+ const isEmpty = merged.Color == undefined && merged.Height == undefined;
313
+ update({ Bar: isEmpty ? undefined : merged });
298
314
  };
299
315
  // -- Marker ----------------------------------------------------------------
300
316
  const updateMarker = (patch) => {
301
- update({
302
- TargetMarker: {
317
+ updateTargetProperties({
318
+ Marker: {
303
319
  Shape: 'Line',
304
- ...bullet.TargetMarker,
320
+ ...bullet.TargetProperties?.Marker,
305
321
  ...patch,
306
322
  },
307
323
  });
308
324
  };
309
325
  // -- Cell text -------------------------------------------------------------
310
- const toggleCellText = (token, checked) => {
311
- const current = bullet.CellText ?? [];
312
- const next = checked
313
- ? Array.from(new Set([...current, token]))
314
- : current.filter((t) => t !== token);
315
- update({ CellText: next });
326
+ const toggleCellText = (token, show) => {
327
+ update(toggleBarChartCellTextToken(bullet.CellTextProperties, token, show));
328
+ };
329
+ const onCellTextPlacementChange = (token, patch) => {
330
+ update({
331
+ CellTextProperties: patchBarChartCellTextPlacement(bullet.CellTextProperties, token, patch),
332
+ });
316
333
  };
317
334
  const toggleToolTipText = (token, checked) => {
318
335
  const current = bullet.ToolTipText ?? [];
@@ -321,9 +338,6 @@ export const StyledColumnWizardBulletSection = (props) => {
321
338
  : current.filter((t) => t !== token);
322
339
  update({ ToolTipText: next });
323
340
  };
324
- const handleCellTextPositionChange = (pos) => {
325
- update({ CellTextPosition: pos });
326
- };
327
341
  // -------------------------------------------------------------------------
328
342
  // Render
329
343
  // -------------------------------------------------------------------------
@@ -336,22 +350,27 @@ export const StyledColumnWizardBulletSection = (props) => {
336
350
  if (variant === 'ranges') {
337
351
  return (_jsx(Box, { children: _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Ranges" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Define qualitative bands for the bullet scale" })] }), _jsx(Card.Body, { children: _jsx(RangesComponent, { disabled: disabled, minMaxRangeValues: minMaxRangeValues, api: api, scope: scope, ranges: bullet.CellRanges, rangeValueType: bullet.RangeValueType, onRangeValueTypeChange: onRangeValueTypeChange, columnComparison: bullet.ColumnComparison, updateRanges: onUpdateRanges, updateColumnComparison: onUpdateColumnComparison, hideColumnComparison: true }) })] }) }));
338
352
  }
339
- const numericTargetValue = typeof bullet.Target === 'number'
340
- ? bullet.Target
341
- : typeof bullet.Target?.Value === 'number'
342
- ? bullet.Target.Value
353
+ const primaryTarget = Array.isArray(bullet.TargetProperties?.Target)
354
+ ? bullet.TargetProperties?.Target?.[0]
355
+ : bullet.TargetProperties?.Target;
356
+ const numericTargetValue = typeof primaryTarget === 'number'
357
+ ? primaryTarget
358
+ : typeof primaryTarget?.Value === 'number'
359
+ ? primaryTarget.Value
343
360
  : undefined;
344
- const columnTargetValue = typeof bullet.Target === 'string' && bullet.Target !== 'Col-Avg' && bullet.Target !== 'Col-Median'
345
- ? bullet.Target
346
- : typeof bullet.Target?.Value === 'string'
347
- ? bullet.Target.Value
361
+ const columnTargetValue = typeof primaryTarget === 'string' && primaryTarget !== 'Col-Avg' && primaryTarget !== 'Col-Median'
362
+ ? primaryTarget
363
+ : typeof primaryTarget?.Value === 'string'
364
+ ? primaryTarget.Value
348
365
  : undefined;
366
+ const markerCfg = bullet.TargetProperties?.Marker;
349
367
  const marker = {
350
- Shape: bullet.TargetMarker?.Shape ?? 'Line',
351
- Color: bullet.TargetMarker?.Color ?? '',
352
- Size: bullet.TargetMarker?.Size ?? (bullet.TargetMarker?.Shape === 'Line' ? 2 : 8),
368
+ Shape: markerCfg?.Shape ?? 'Line',
369
+ Color: markerCfg?.Color ?? '',
370
+ Size: markerCfg?.Size ?? (markerCfg?.Shape === 'Line' ? 2 : 8),
353
371
  };
354
- const cellTextDisabled = ArrayExtensions.IsNullOrEmpty(bullet.CellText) || disabled;
372
+ const cellTextProperties = bullet.CellTextProperties;
373
+ const cellTextDisabled = !hasBarChartCellTextConfigured(cellTextProperties) || disabled;
355
374
  return (_jsxs(Box, { children: [_jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Target" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Select a target value for the bullet scale" })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Target:", children: _jsx(Box, { className: "twa:max-w-[180px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: currentMode, onValueChange: (v) => handleTargetModeChange(v), items: [
356
375
  { value: 'None', label: 'None' },
357
376
  { value: 'Number', label: 'Fixed Number' },
@@ -361,8 +380,8 @@ export const StyledColumnWizardBulletSection = (props) => {
361
380
  ] }) }) }), currentMode === 'Number' && (_jsx(FormRow, { label: "Target Value:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(AdaptableInput, { type: "number", value: numericTargetValue ?? '', onChange: (e) => handleNumericTargetChange(e.target.value === '' ? undefined : Number(e.target.value)) }) }) })), currentMode === 'Column' && (_jsx(FormRow, { label: "Target Column:", children: _jsx(Box, { className: "twa:max-w-[220px]", children: _jsx(ColumnSelector, { type: "number", value: columnTargetValue ?? '', onChange: handleColumnTargetChange, filterColumn: (c) => c.columnId !== data.ColumnId, placeholder: "Select numeric column" }) }) })), currentMode !== 'None' && (_jsxs(_Fragment, { children: [_jsx(FormRow, { label: "Marker Shape:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: marker.Shape, onValueChange: (s) => updateMarker({ Shape: s }), items: MARKER_SHAPES.map((s) => ({ value: s.value, label: s.label })) }) }) }), _jsx(FormRow, { label: "Marker Colour:", children: _jsx(ColorPicker, { disabled: disabled, api: api, value: marker.Color || undefined, onChange: (c) => updateMarker({ Color: c }) }) }), _jsx(FormRow, { label: "Marker Size:", children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: marker.Size, onChange: (e) => updateMarker({ Size: Number(e.target.value) }) }) }) })] }))] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Bar" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Set the bar orientation and height" })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Orientation:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: bullet.Orientation ?? 'Horizontal', onValueChange: (v) => update({ Orientation: v }), items: [
362
381
  { value: 'Horizontal', label: 'Horizontal' },
363
382
  { value: 'Vertical', label: 'Vertical' },
364
- ] }) }) }), bullet.Orientation === 'Vertical' && (_jsx(FormRow, { label: "", children: _jsxs(Box, { className: "twa:text-xs twa:text-neutral-500", children: ["Tip: vertical bullet charts need a tall row height to be readable (we recommend at least 60px). Set ", _jsx("code", { children: "rowHeight" }), " on ", _jsx("code", { children: " gridOptions " }), " or use", ' ', _jsx("code", { children: "getRowHeight" }), "."] }) })), _jsx(FormRow, { label: "Bar Colour:", children: _jsx(ColorPicker, { disabled: disabled, api: api, value: bullet.BarColor, onChange: (c) => update({ BarColor: c }) }) }), _jsx(FormRow, { label: bullet.Orientation === 'Vertical' ? 'Bar Width (px):' : 'Bar Height (px):', children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: bullet.BarHeight ?? '', onChange: (e) => update({
365
- BarHeight: e.target.value === '' ? undefined : Number(e.target.value),
383
+ ] }) }) }), bullet.Orientation === 'Vertical' && (_jsx(FormRow, { label: "", children: _jsxs(Box, { className: "twa:text-xs twa:text-neutral-500", children: ["Tip: vertical bullet charts need a tall row height to be readable (we recommend at least 60px). Set ", _jsx("code", { children: "rowHeight" }), " on ", _jsx("code", { children: " gridOptions " }), " or use", ' ', _jsx("code", { children: "getRowHeight" }), "."] }) })), _jsx(FormRow, { label: "Bar Colour:", children: _jsx(ColorPicker, { disabled: disabled, api: api, value: bullet.Bar?.Color, onChange: (c) => updateBar({ Color: c }) }) }), _jsx(FormRow, { label: bullet.Orientation === 'Vertical' ? 'Bar Width (px):' : 'Bar Height (px):', children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: bullet.Bar?.Height ?? '', onChange: (e) => updateBar({
384
+ Height: e.target.value === '' ? undefined : Number(e.target.value),
366
385
  }), placeholder: "8" }) }) }), _jsx(FormRow, { label: "Origin:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: typeof bullet.Origin === 'number' ? 'Number' : (bullet.Origin ?? 'Auto'), onValueChange: (v) => {
367
386
  if (v === 'Auto' || v === 'Zero') {
368
387
  update({ Origin: v });
@@ -373,11 +392,7 @@ export const StyledColumnWizardBulletSection = (props) => {
373
392
  }, items: [
374
393
  { value: 'Auto', label: 'Auto' },
375
394
  { value: 'Zero', label: 'Zero' },
376
- ] }) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Cell Text" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Choose whether to display text in the cell (and if so, then position and font))" })] }), _jsxs(Card.Body, { children: [_jsxs(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: [_jsxs(FormRow, { label: "Cell Display:", children: [_jsx(CheckBox, { disabled: disabled, checked: bullet.CellText?.includes('CellValue'), onChange: (checked) => toggleCellText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { disabled: disabled, className: "twa:ml-3", checked: bullet.CellText?.includes('PercentageValue'), onChange: (checked) => toggleCellText('PercentageValue', checked), children: "Percent Value" })] }), _jsx(FormRow, { label: "Cell Display Position:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", disabled: cellTextDisabled, value: bullet.CellTextPosition ?? 'Below', onValueChange: (v) => handleCellTextPositionChange(v), items: [
377
- { value: 'Above', label: 'Above Bar' },
378
- { value: 'Below', label: 'Below Bar' },
379
- { value: 'Merged', label: 'Merged' },
380
- ] }) }) })] }), _jsx(Box, { className: `twa:mt-3 twa:pt-3 twa:border-t twa:border-foreground/15 ${cellTextDisabled ? 'twa:opacity-50' : ''}`, children: _jsx(StyledColumnFontStyleEditor, { api: api, disabled: cellTextDisabled, value: bullet.Font, onChange: (next) => {
395
+ ] }) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Cell Text" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Pick which values to display and where each one sits around the bar" })] }), _jsxs(Card.Body, { children: [_jsx(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: _jsx(FormRow, { label: "Cell Text Layout:", children: _jsx(BarChartCellTextLayoutEditor, { disabled: disabled, cellTextProperties: cellTextProperties, onToggle: toggleCellText, onPlacementChange: onCellTextPlacementChange }) }) }), _jsx(Box, { className: `twa:mt-3 twa:pt-3 twa:border-t twa:border-foreground/15 ${cellTextDisabled ? 'twa:opacity-50' : ''}`, children: _jsx(StyledColumnFontStyleEditor, { api: api, disabled: cellTextDisabled, value: bullet.Font, onChange: (next) => {
381
396
  if (next) {
382
397
  update({ Font: next });
383
398
  }
@@ -78,8 +78,9 @@ export const getStyledColumnIconMappingsViewValues = (data) => {
78
78
  if (ic.MatchMode && ic.MatchMode !== 'Exact') {
79
79
  items.push(`Match Mode: ${ic.MatchMode}`);
80
80
  }
81
- if (ic.Fallback && ic.Fallback !== 'Hide') {
82
- items.push(`Fallback: ${ic.Fallback}`);
81
+ const fallbackMode = ic.FallbackProperties?.Mode;
82
+ if (fallbackMode && fallbackMode !== 'Hide') {
83
+ items.push(`Fallback: ${fallbackMode}`);
83
84
  }
84
85
  return items;
85
86
  };
@@ -91,9 +92,10 @@ const buildStyledColumnIconStyleSummaryStrings = (ic, options) => {
91
92
  if (ic.Gap != null) {
92
93
  items.push(`Gap: ${ic.Gap}px`);
93
94
  }
94
- if (ic.CellText?.length) {
95
- items.push(`Cell Text: ${formatIconCellTextSummary(ic.CellText)}`);
96
- items.push(`Cell Text Position: ${ic.CellTextPosition ?? 'After'}`);
95
+ const ctp = ic.CellTextProperties;
96
+ if (ctp?.CellText?.length) {
97
+ items.push(`Cell Text: ${formatIconCellTextSummary(ctp.CellText)}`);
98
+ items.push(`Cell Text Position: ${ctp.CellTextPosition ?? 'After'}`);
97
99
  }
98
100
  else if (options.includeEmptyCellText) {
99
101
  items.push('Cell Text: None');
@@ -253,12 +255,35 @@ export const StyledColumnWizardIconSection = (props) => {
253
255
  // -----------------------------------------------------------------------
254
256
  // CellText helpers
255
257
  // -----------------------------------------------------------------------
258
+ const updateCellTextProperties = (patch) => {
259
+ const merged = {
260
+ ...iconStyle.CellTextProperties,
261
+ ...patch,
262
+ };
263
+ // Strip the wrapper when both inner properties are unset, so empty state
264
+ // serialises cleanly.
265
+ const isEmpty = !merged.CellText?.length && merged.CellTextPosition == undefined;
266
+ update({ CellTextProperties: isEmpty ? undefined : merged });
267
+ };
256
268
  const toggleCellText = (token, checked) => {
257
- const current = iconStyle.CellText ?? [];
269
+ const current = iconStyle.CellTextProperties?.CellText ?? [];
258
270
  const next = checked
259
271
  ? Array.from(new Set([...current, token]))
260
272
  : current.filter((t) => t !== token);
261
- update({ CellText: next });
273
+ updateCellTextProperties({ CellText: next });
274
+ };
275
+ // -----------------------------------------------------------------------
276
+ // Fallback helpers
277
+ // -----------------------------------------------------------------------
278
+ const updateFallbackProperties = (patch) => {
279
+ const merged = {
280
+ ...iconStyle.FallbackProperties,
281
+ ...patch,
282
+ };
283
+ // Strip the wrapper when there's nothing to remember; the renderer
284
+ // already defaults to `Mode: 'Hide'` when `FallbackProperties` is unset.
285
+ const isEmpty = (merged.Mode == undefined || merged.Mode === 'Hide') && merged.Icon == undefined;
286
+ update({ FallbackProperties: isEmpty ? undefined : merged });
262
287
  };
263
288
  const toggleToolTipText = (token, checked) => {
264
289
  const current = iconStyle.ToolTipText ?? [];
@@ -287,14 +312,14 @@ export const StyledColumnWizardIconSection = (props) => {
287
312
  }), placeholder: "Tooltip label (optional)" }) }), _jsx(Box, { className: "twa:w-8 twa:shrink-0 twa:flex twa:justify-center", children: _jsx(SimpleButton, { icon: "delete", variant: "text", tooltip: "Remove mapping", onClick: () => removeMapping(i) }) })] }, i)))] })), _jsx(Box, { className: "twa:mt-2", children: _jsx(ButtonNew, { onClick: addMapping, children: "Add Mapping" }) })] })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Matching" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "How keys are compared to cell values, and what to render when no mapping matches" })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { children: [_jsx(FormRow, { label: "Match Mode:", children: _jsx(Box, { className: "twa:max-w-[200px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: iconStyle.MatchMode ?? 'Exact', onValueChange: (v) => update({ MatchMode: v }), items: [
288
313
  { value: 'Exact', label: 'Exact Match Required' },
289
314
  { value: 'CaseInsensitive', label: 'Case-insensitive (strings)' },
290
- ] }) }) }), _jsx(FormRow, { label: "Fallback:", children: _jsx(Box, { className: "twa:max-w-[200px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: iconStyle.Fallback ?? 'Hide', onValueChange: (v) => update({ Fallback: v }), items: [
315
+ ] }) }) }), _jsx(FormRow, { label: "Fallback:", children: _jsx(Box, { className: "twa:max-w-[200px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: iconStyle.FallbackProperties?.Mode ?? 'Hide', onValueChange: (v) => updateFallbackProperties({ Mode: v }), items: [
291
316
  { value: 'Hide', label: 'Show No Value' },
292
317
  { value: 'ShowText', label: 'Show Raw Value' },
293
318
  { value: 'Icon', label: 'Show Fallback Icon' },
294
- ] }) }) }), iconStyle.Fallback === 'Icon' && (_jsx(FormRow, { label: "Fallback Icon:", children: _jsx(IconPickerButton, { value: iconStyle.FallbackIcon, onChange: (next) => update({ FallbackIcon: next }) }) }))] }) })] })] }));
319
+ ] }) }) }), iconStyle.FallbackProperties?.Mode === 'Icon' && (_jsx(FormRow, { label: "Fallback Icon:", children: _jsx(IconPickerButton, { value: iconStyle.FallbackProperties?.Icon, onChange: (next) => updateFallbackProperties({ Icon: next }) }) }))] }) })] })] }));
295
320
  }
296
321
  // ----- Style variant (wizard step title: "Style") ------------------------
297
- const cellText = iconStyle.CellText ?? [];
322
+ const cellText = iconStyle.CellTextProperties?.CellText ?? [];
298
323
  const toolTipText = iconStyle.ToolTipText ?? [];
299
324
  const cellTextDisabled = cellText.length === 0;
300
325
  return (_jsxs(Box, { children: [_jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsx(Card.Title, { children: "Sizing" }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Icon Size (px):", children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(Input, { type: "number", min: 8, step: 1, value: iconStyle.Size ?? '', placeholder: "18", className: "twa:w-full", onChange: (event) => {
@@ -307,7 +332,9 @@ export const StyledColumnWizardIconSection = (props) => {
307
332
  update({
308
333
  Size: Number.isFinite(parsed) && parsed >= 8 ? parsed : undefined,
309
334
  });
310
- } }) }) }), _jsx(FormRow, { label: "Gap (px):", children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(NumberInput, { value: iconStyle.Gap ?? '', placeholder: "4", min: 0, step: 1, onChange: (value) => update({ Gap: typeof value === 'number' ? value : undefined }) }) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Cell Text" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Optionally show the raw value or the matched description alongside the icon (e.g. flag plus label)." })] }), _jsxs(Card.Body, { children: [_jsxs(FormLayout, { sizes: [...STYLE_FORM_SIZES], children: [_jsxs(FormRow, { label: "Cell Display:", children: [_jsx(CheckBox, { checked: cellText.includes('CellValue'), onChange: (checked) => toggleCellText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { className: "twa:ml-3", checked: cellText.includes('IconDescription'), onChange: (checked) => toggleCellText('IconDescription', checked), children: "Description" })] }), _jsx(FormRow, { label: "Position:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: iconStyle.CellTextPosition ?? 'After', onValueChange: (v) => update({ CellTextPosition: v }), items: [
335
+ } }) }) }), _jsx(FormRow, { label: "Gap (px):", children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(NumberInput, { value: iconStyle.Gap ?? '', placeholder: "4", min: 0, step: 1, onChange: (value) => update({ Gap: typeof value === 'number' ? value : undefined }) }) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Cell Text" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Optionally show the raw value or the matched description alongside the icon (e.g. flag plus label)." })] }), _jsxs(Card.Body, { children: [_jsxs(FormLayout, { sizes: [...STYLE_FORM_SIZES], children: [_jsxs(FormRow, { label: "Cell Display:", children: [_jsx(CheckBox, { checked: cellText.includes('CellValue'), onChange: (checked) => toggleCellText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { className: "twa:ml-3", checked: cellText.includes('IconDescription'), onChange: (checked) => toggleCellText('IconDescription', checked), children: "Description" })] }), _jsx(FormRow, { label: "Position:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: iconStyle.CellTextProperties?.CellTextPosition ?? 'After', onValueChange: (v) => updateCellTextProperties({
336
+ CellTextPosition: v,
337
+ }), items: [
311
338
  { value: 'Before', label: 'Before' },
312
339
  { value: 'After', label: 'After' },
313
340
  { value: 'Above', label: 'Above' },
@@ -10,7 +10,6 @@ import { RangesComponent } from '../../Components/RangesComponent';
10
10
  import { ColumnSelector } from '../../Components/Selectors/ColumnSelector';
11
11
  import { getGraySwatchColor } from '../../UIHelper';
12
12
  import { useOnePageAdaptableWizardContext } from '../../Wizard/OnePageAdaptableWizard';
13
- import ArrayExtensions from '../../../Utilities/Extensions/ArrayExtensions';
14
13
  import AdaptableInput from '../../Components/AdaptableInput';
15
14
  import { Box, Flex } from '../../../components/Flex';
16
15
  import { SingleSelect } from '../../../components/NewSelect';
@@ -18,6 +17,8 @@ import { RangeBarRangesSummaryPreview } from './StyledColumnWizardStyleSection/C
18
17
  import { StyledColumnRangeBarPreviewCard } from './StyledColumnWizardStyleSection/Components/StyledColumnRangeBarPreview';
19
18
  import { Card } from '../../../components/Card';
20
19
  import { renderSummaryStringTags } from '../../Wizard/SummaryColorTag';
20
+ import { formatBarChartCellTextLayoutSummary, getActiveBarChartCellTextTokens, hasBarChartCellTextConfigured, patchBarChartCellTextPlacement, resolveBarChartCellTextLayout, toggleBarChartCellTextToken, } from '../../../Utilities/Helpers/barChartCellText';
21
+ import { BarChartCellTextLayoutEditor } from './StyledColumnWizardStyleSection/Components/BarChartCellTextLayoutEditor';
21
22
  const RANGE_STYLE_FORM_SIZES = ['200px', '1fr'];
22
23
  const BOUND_MODE_LABELS = {
23
24
  Number: 'Fixed Number',
@@ -122,8 +123,8 @@ export const getStyledColumnRangeBarRangeViewValues = (data) => {
122
123
  `Min: ${summarizeBound(range.Min)}`,
123
124
  `Max: ${summarizeBound(range.Max)}`,
124
125
  ];
125
- if (range.Reference != undefined) {
126
- items.push(`Reference: ${summarizeBound(range.Reference)}`);
126
+ if (range.Reference?.Value != undefined) {
127
+ items.push(`Reference: ${summarizeBound(range.Reference.Value)}`);
127
128
  }
128
129
  const bandCount = range.CellRanges?.length ?? 0;
129
130
  if (bandCount > 0) {
@@ -137,7 +138,8 @@ export const getStyledColumnRangeBarRangeViewValues = (data) => {
137
138
  const buildStyledColumnRangeBarDisplaySummaryStrings = (range, options) => {
138
139
  const items = [];
139
140
  const valueMarker = range.Marker;
140
- const referenceMarker = range.ReferenceMarker;
141
+ const referenceProperties = range.Reference;
142
+ const referenceMarker = referenceProperties?.Marker;
141
143
  items.push(`Value Marker Shape: ${valueMarker?.Shape ?? 'Diamond'}`);
142
144
  if (valueMarker?.Color) {
143
145
  items.push(`Value Marker Colour: ${valueMarker.Color}`);
@@ -145,7 +147,7 @@ const buildStyledColumnRangeBarDisplaySummaryStrings = (range, options) => {
145
147
  if (valueMarker?.Size != null) {
146
148
  items.push(`Value Marker Size: ${valueMarker.Size}px`);
147
149
  }
148
- if (range.Reference != undefined) {
150
+ if (referenceProperties?.Value != undefined) {
149
151
  items.push(`Reference Marker Shape: ${referenceMarker?.Shape ?? 'Line'}`);
150
152
  if (referenceMarker?.Color) {
151
153
  items.push(`Reference Marker Colour: ${referenceMarker.Color}`);
@@ -157,25 +159,31 @@ const buildStyledColumnRangeBarDisplaySummaryStrings = (range, options) => {
157
159
  if (range.Orientation === 'Vertical') {
158
160
  items.push('Orientation: Vertical');
159
161
  }
160
- const outOfRangeMode = range.OutOfRangeMode ?? 'Clamp';
162
+ const outOfRangeProperties = range.OutOfRange;
163
+ const outOfRangeMode = outOfRangeProperties?.Mode ?? 'Clamp';
161
164
  if (outOfRangeMode !== 'Clamp') {
162
165
  items.push(`Out of Range: ${outOfRangeMode}`);
163
166
  }
164
- if (range.OutOfRangeColor) {
165
- items.push(`Out of Range Colour: ${range.OutOfRangeColor}`);
167
+ if (outOfRangeProperties?.Color) {
168
+ items.push(`Out of Range Colour: ${outOfRangeProperties.Color}`);
166
169
  }
167
- if (range.TrackColor) {
168
- items.push(`Track Colour: ${range.TrackColor}`);
170
+ const trackProperties = range.Track;
171
+ if (trackProperties?.Color) {
172
+ items.push(`Track Colour: ${trackProperties.Color}`);
169
173
  }
170
- if (range.TrackHeight != null) {
171
- items.push(`Track Height: ${range.TrackHeight}px`);
174
+ if (trackProperties?.Height != null) {
175
+ items.push(`Track Height: ${trackProperties.Height}px`);
172
176
  }
173
177
  if (range.BackColor) {
174
178
  items.push(`Back Colour: ${range.BackColor}`);
175
179
  }
176
- if (range.CellText?.length) {
177
- items.push(`Cell Text: ${formatRangeBarCellTextSummary(range.CellText)}`);
178
- items.push(`Cell Text Position: ${range.CellTextPosition ?? 'Below'}`);
180
+ if (hasBarChartCellTextConfigured(range.CellTextProperties)) {
181
+ const tokens = getActiveBarChartCellTextTokens(range.CellTextProperties);
182
+ items.push(`Cell Text: ${formatRangeBarCellTextSummary(tokens)}`);
183
+ const layoutSummary = formatBarChartCellTextLayoutSummary(resolveBarChartCellTextLayout(range.CellTextProperties));
184
+ if (layoutSummary) {
185
+ items.push(`Placement: ${layoutSummary}`);
186
+ }
179
187
  }
180
188
  else if (options.includeEmptyCellText) {
181
189
  items.push('Cell Text: None');
@@ -321,15 +329,41 @@ export const StyledColumnWizardRangeBarSection = (props) => {
321
329
  },
322
330
  });
323
331
  }, [data, range]);
324
- const updateOptionalColor = (key, color) => {
332
+ const updateBackColor = (color) => {
325
333
  if (color) {
326
- update({ [key]: color });
334
+ update({ BackColor: color });
327
335
  return;
328
336
  }
329
337
  const next = { ...range };
330
- delete next[key];
338
+ delete next.BackColor;
331
339
  props.onChange({ ...data, RangeBarStyle: next });
332
340
  };
341
+ const updateTrackProperties = (patch) => {
342
+ const merged = {
343
+ ...range.Track,
344
+ ...patch,
345
+ };
346
+ const isEmpty = merged.Color == undefined && merged.Height == undefined;
347
+ update({ Track: isEmpty ? undefined : merged });
348
+ };
349
+ const updateOutOfRangeProperties = (patch) => {
350
+ const merged = {
351
+ ...range.OutOfRange,
352
+ ...patch,
353
+ };
354
+ // Default mode is `Clamp` with no override colour; drop the wrapper in
355
+ // that case so empty state serialises cleanly.
356
+ const isEmpty = (merged.Mode == undefined || merged.Mode === 'Clamp') && merged.Color == undefined;
357
+ update({ OutOfRange: isEmpty ? undefined : merged });
358
+ };
359
+ const updateReferenceProperties = (patch) => {
360
+ const merged = {
361
+ Value: range.Reference?.Value,
362
+ ...range.Reference,
363
+ ...patch,
364
+ };
365
+ update({ Reference: merged });
366
+ };
333
367
  // -- Bound editors ---------------------------------------------------------
334
368
  // Resolved values for the column-wide aggregate bound modes, shown read-only
335
369
  // in the bound editor so the user sees the underlying number.
@@ -348,6 +382,16 @@ export const StyledColumnWizardRangeBarSection = (props) => {
348
382
  */
349
383
  const renderBoundEditor = (opts) => {
350
384
  const setBound = (next) => {
385
+ if (opts.field === 'Reference') {
386
+ if (next === undefined) {
387
+ const cleaned = { ...range };
388
+ delete cleaned.Reference;
389
+ props.onChange({ ...data, RangeBarStyle: cleaned });
390
+ return;
391
+ }
392
+ updateReferenceProperties({ Value: next });
393
+ return;
394
+ }
351
395
  if (next === undefined) {
352
396
  const cleaned = { ...range };
353
397
  delete cleaned[opts.field];
@@ -356,7 +400,8 @@ export const StyledColumnWizardRangeBarSection = (props) => {
356
400
  }
357
401
  update({ [opts.field]: next });
358
402
  };
359
- return (_jsx(FormRow, { label: `${opts.label}:`, children: _jsx(RangeBarBoundInput, { api: api, value: range[opts.field], optional: opts.optional, fallbackNumber: opts.fallbackNumber, excludeColumnId: data.ColumnId, resolved: resolvedBoundValues, disabled: disabled, onChange: setBound }) }));
403
+ const value = opts.field === 'Reference' ? range.Reference?.Value : range[opts.field];
404
+ return (_jsx(FormRow, { label: `${opts.label}:`, children: _jsx(RangeBarBoundInput, { api: api, value: value, optional: opts.optional, fallbackNumber: opts.fallbackNumber, excludeColumnId: data.ColumnId, resolved: resolvedBoundValues, disabled: disabled, onChange: setBound }) }));
360
405
  };
361
406
  // -- Marker editors --------------------------------------------------------
362
407
  const updateValueMarker = (patch) => {
@@ -369,10 +414,10 @@ export const StyledColumnWizardRangeBarSection = (props) => {
369
414
  });
370
415
  };
371
416
  const updateReferenceMarker = (patch) => {
372
- update({
373
- ReferenceMarker: {
417
+ updateReferenceProperties({
418
+ Marker: {
374
419
  Shape: 'Line',
375
- ...range.ReferenceMarker,
420
+ ...range.Reference?.Marker,
376
421
  ...patch,
377
422
  },
378
423
  });
@@ -384,18 +429,20 @@ export const StyledColumnWizardRangeBarSection = (props) => {
384
429
  Color: range.Marker?.Color ?? '',
385
430
  Size: range.Marker?.Size ?? (range.Marker?.Shape === 'Line' ? 2 : 10),
386
431
  };
432
+ const referenceMarkerCfg = range.Reference?.Marker;
387
433
  const referenceMarker = {
388
- Shape: range.ReferenceMarker?.Shape ?? 'Line',
389
- Color: range.ReferenceMarker?.Color ?? '',
390
- Size: range.ReferenceMarker?.Size ?? (range.ReferenceMarker?.Shape === 'Line' ? 2 : 8),
434
+ Shape: referenceMarkerCfg?.Shape ?? 'Line',
435
+ Color: referenceMarkerCfg?.Color ?? '',
436
+ Size: referenceMarkerCfg?.Size ?? (referenceMarkerCfg?.Shape === 'Line' ? 2 : 8),
391
437
  };
392
438
  // -- Cell text -------------------------------------------------------------
393
- const toggleCellText = (token, checked) => {
394
- const current = range.CellText ?? [];
395
- const next = checked
396
- ? Array.from(new Set([...current, token]))
397
- : current.filter((t) => t !== token);
398
- update({ CellText: next });
439
+ const toggleCellText = (token, show) => {
440
+ update(toggleBarChartCellTextToken(range.CellTextProperties, token, show));
441
+ };
442
+ const onCellTextPlacementChange = (token, patch) => {
443
+ update({
444
+ CellTextProperties: patchBarChartCellTextPlacement(range.CellTextProperties, token, patch),
445
+ });
399
446
  };
400
447
  const toggleToolTipText = (token, checked) => {
401
448
  const current = range.ToolTipText ?? [];
@@ -404,9 +451,6 @@ export const StyledColumnWizardRangeBarSection = (props) => {
404
451
  : current.filter((t) => t !== token);
405
452
  update({ ToolTipText: next });
406
453
  };
407
- const handleCellTextPositionChange = (pos) => {
408
- update({ CellTextPosition: pos });
409
- };
410
454
  // -------------------------------------------------------------------------
411
455
  // Render
412
456
  // -------------------------------------------------------------------------
@@ -415,8 +459,8 @@ export const StyledColumnWizardRangeBarSection = (props) => {
415
459
  ? 'You need to select a column before styling.'
416
460
  : `Column "${data.ColumnId}" was not found in the grid.` }) }));
417
461
  }
418
- const hasReference = range.Reference != undefined;
419
- const outOfRangeMode = range.OutOfRangeMode ?? 'Clamp';
462
+ const hasReference = range.Reference?.Value != undefined;
463
+ const outOfRangeMode = range.OutOfRange?.Mode ?? 'Clamp';
420
464
  const isRangeVariant = props.variant === 'range';
421
465
  return (_jsxs(Box, { children: [isRangeVariant && (_jsxs(_Fragment, { children: [_jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Bounds" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Set each row's track scale. A bound can be a fixed number, another column's value (read per row), or a column-wide aggregate (min, max, average, median). Reference is an optional second marker." })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [renderBoundEditor({
422
466
  label: 'Min',
@@ -438,15 +482,13 @@ export const StyledColumnWizardRangeBarSection = (props) => {
438
482
  : 'Optional second marker when a Reference bound is set on the Style step.' })] }), _jsx(Card.Body, { children: hasReference ? (_jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Shape:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: referenceMarker.Shape, onValueChange: (s) => updateReferenceMarker({ Shape: s }), items: MARKER_SHAPES.map((s) => ({ value: s.value, label: s.label })) }) }) }), _jsx(FormRow, { label: `${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(ColorPicker, { disabled: disabled, api: api, value: referenceMarker.Color || undefined, onChange: (c) => updateReferenceMarker({ Color: c }) }) }), _jsx(FormRow, { label: "Size:", children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: referenceMarker.Size, onChange: (e) => updateReferenceMarker({ Size: Number(e.target.value) }) }) }) })] })) : (_jsx(Box, { className: "twa:text-xs twa:opacity-60 twa:max-w-[520px]", children: "Add a Reference value on the Style step (Bounds section) to enable this marker (e.g. previous close, target, midpoint)." })) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Track" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "The line representing the [Min, Max] interval, plus optional cell background." })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Orientation:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: range.Orientation ?? 'Horizontal', onValueChange: (v) => update({ Orientation: v }), items: [
439
483
  { value: 'Horizontal', label: 'Horizontal' },
440
484
  { value: 'Vertical', label: 'Vertical' },
441
- ] }) }) }), range.Orientation === 'Vertical' && (_jsx(FormRow, { label: "", children: _jsxs(Box, { className: "twa:text-xs twa:text-neutral-500 twa:max-w-[520px]", children: ["Tip: vertical Range Bars need a tall row height to be readable (we recommend at least 60px). Set ", _jsx("code", { children: "rowHeight" }), " on ", _jsx("code", { children: " gridOptions " }), " or use ", _jsx("code", { children: "getRowHeight" }), "."] }) })), _jsx(FormRow, { label: `Track ${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(OptionalColorPicker, { disabled: disabled, api: api, value: range.TrackColor, defaultColor: getGraySwatchColor(), onChange: (c) => updateOptionalColor('TrackColor', c) }) }), _jsx(FormRow, { label: range.Orientation === 'Vertical' ? 'Track Width (px):' : 'Track Height (px):', children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: range.TrackHeight ?? '', onChange: (e) => update({
442
- TrackHeight: e.target.value === '' ? undefined : Number(e.target.value),
443
- }), placeholder: "4" }) }) }), _jsx(FormRow, { label: `Back ${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(OptionalColorPicker, { disabled: disabled, api: api, value: range.BackColor ?? undefined, defaultColor: getGraySwatchColor(), onChange: (c) => updateOptionalColor('BackColor', c) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Out of Range" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "How to draw the value marker when the cell value falls outside [Min, Max]." })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Behaviour:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: outOfRangeMode, onValueChange: (v) => update({ OutOfRangeMode: v }), items: [
485
+ ] }) }) }), range.Orientation === 'Vertical' && (_jsx(FormRow, { label: "", children: _jsxs(Box, { className: "twa:text-xs twa:text-neutral-500 twa:max-w-[520px]", children: ["Tip: vertical Range Bars need a tall row height to be readable (we recommend at least 60px). Set ", _jsx("code", { children: "rowHeight" }), " on ", _jsx("code", { children: " gridOptions " }), " or use ", _jsx("code", { children: "getRowHeight" }), "."] }) })), _jsx(FormRow, { label: `Track ${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(OptionalColorPicker, { disabled: disabled, api: api, value: range.Track?.Color, defaultColor: getGraySwatchColor(), onChange: (c) => updateTrackProperties({ Color: c }) }) }), _jsx(FormRow, { label: range.Orientation === 'Vertical' ? 'Track Width (px):' : 'Track Height (px):', children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: range.Track?.Height ?? '', onChange: (e) => updateTrackProperties({
486
+ Height: e.target.value === '' ? undefined : Number(e.target.value),
487
+ }), placeholder: "4" }) }) }), _jsx(FormRow, { label: `Back ${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(OptionalColorPicker, { disabled: disabled, api: api, value: range.BackColor ?? undefined, defaultColor: getGraySwatchColor(), onChange: (c) => updateBackColor(c) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Out of Range" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "How to draw the value marker when the cell value falls outside [Min, Max]." })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Behaviour:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: outOfRangeMode, onValueChange: (v) => updateOutOfRangeProperties({
488
+ Mode: v,
489
+ }), items: [
444
490
  { value: 'Clamp', label: 'Clamp to edge' },
445
491
  { value: 'Overflow', label: 'Show outside' },
446
492
  { value: 'Hide', label: 'Hide marker' },
447
- ] }) }) }), outOfRangeMode === 'Clamp' && (_jsx(FormRow, { label: `Out-of-range ${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(OptionalColorPicker, { disabled: disabled, api: api, value: range.OutOfRangeColor, defaultColor: "crimson", onChange: (c) => updateOptionalColor('OutOfRangeColor', c) }) }))] }) })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Text & Tooltip" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Optional cell-text overlay and AG Grid tooltip content." })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [_jsxs(FormRow, { label: "Cell Display:", children: [_jsx(CheckBox, { disabled: disabled, checked: range.CellText?.includes('CellValue'), onChange: (checked) => toggleCellText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { disabled: disabled, className: "twa:ml-3", checked: range.CellText?.includes('PercentageValue'), onChange: (checked) => toggleCellText('PercentageValue', checked), children: "Percent Value" })] }), _jsx(FormRow, { label: "Cell Display Position:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", disabled: ArrayExtensions.IsNullOrEmpty(range.CellText) || disabled, value: range.CellTextPosition ?? 'Below', onValueChange: (v) => handleCellTextPositionChange(v), items: [
448
- { value: 'Above', label: 'Above Bar' },
449
- { value: 'Below', label: 'Below Bar' },
450
- { value: 'Merged', label: 'Merged' },
451
- ] }) }) }), _jsxs(FormRow, { label: "Tooltip Display:", children: [_jsx(CheckBox, { disabled: disabled, checked: range.ToolTipText?.includes('CellValue'), onChange: (checked) => toggleToolTipText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { disabled: disabled, className: "twa:ml-3", checked: range.ToolTipText?.includes('PercentageValue'), onChange: (checked) => toggleToolTipText('PercentageValue', checked), children: "Percent Value" })] })] }) })] }), _jsx(StyledColumnRangeBarPreviewCard, { data: data })] }))] }));
493
+ ] }) }) }), outOfRangeMode === 'Clamp' && (_jsx(FormRow, { label: `Out-of-range ${api.internalApi.getCorrectEnglishVariant('Colour')}:`, children: _jsx(OptionalColorPicker, { disabled: disabled, api: api, value: range.OutOfRange?.Color, defaultColor: "crimson", onChange: (c) => updateOutOfRangeProperties({ Color: c }) }) }))] }) })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Text & Tooltip" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Optional cell-text overlay and AG Grid tooltip content." })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...RANGE_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Cell Text Layout:", children: _jsx(BarChartCellTextLayoutEditor, { disabled: disabled, cellTextProperties: range.CellTextProperties, onToggle: toggleCellText, onPlacementChange: onCellTextPlacementChange }) }), _jsxs(FormRow, { label: "Tooltip Display:", children: [_jsx(CheckBox, { disabled: disabled, checked: range.ToolTipText?.includes('CellValue'), onChange: (checked) => toggleToolTipText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { disabled: disabled, className: "twa:ml-3", checked: range.ToolTipText?.includes('PercentageValue'), onChange: (checked) => toggleToolTipText('PercentageValue', checked), children: "Percent Value" })] })] }) })] }), _jsx(StyledColumnRangeBarPreviewCard, { data: data })] }))] }));
452
494
  };