overview-components 1.1.42 → 1.1.44

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 (164) hide show
  1. package/dist/assets/illustration/delete-illustration.js +16 -16
  2. package/dist/components/components-settings/attachments-tab-settings.d.ts.map +1 -1
  3. package/dist/components/components-settings/attachments-tab-settings.js +5 -3
  4. package/dist/components/components-settings/attachments-tab-settings.js.map +1 -1
  5. package/dist/components/components-settings/data-grid-settings.d.ts +31 -2
  6. package/dist/components/components-settings/data-grid-settings.d.ts.map +1 -1
  7. package/dist/components/components-settings/data-grid-settings.js +279 -147
  8. package/dist/components/components-settings/data-grid-settings.js.map +1 -1
  9. package/dist/components/components-settings/section-tab-settings.d.ts +28 -1
  10. package/dist/components/components-settings/section-tab-settings.d.ts.map +1 -1
  11. package/dist/components/components-settings/section-tab-settings.js +439 -125
  12. package/dist/components/components-settings/section-tab-settings.js.map +1 -1
  13. package/dist/components/components-settings/tabs-overview-settings.d.ts.map +1 -1
  14. package/dist/components/components-settings/tabs-overview-settings.js +7 -15
  15. package/dist/components/components-settings/tabs-overview-settings.js.map +1 -1
  16. package/dist/components/index.d.ts +4 -0
  17. package/dist/components/index.d.ts.map +1 -1
  18. package/dist/components/index.js +4 -0
  19. package/dist/components/index.js.map +1 -1
  20. package/dist/components/lit-ai-filter-assistant.d.ts.map +1 -1
  21. package/dist/components/lit-ai-filter-assistant.js +3 -0
  22. package/dist/components/lit-ai-filter-assistant.js.map +1 -1
  23. package/dist/components/lit-attachments-tab.d.ts +1 -0
  24. package/dist/components/lit-attachments-tab.d.ts.map +1 -1
  25. package/dist/components/lit-attachments-tab.js +14 -2
  26. package/dist/components/lit-attachments-tab.js.map +1 -1
  27. package/dist/components/lit-case-variables-tab.d.ts +61 -3
  28. package/dist/components/lit-case-variables-tab.d.ts.map +1 -1
  29. package/dist/components/lit-case-variables-tab.js +1438 -87
  30. package/dist/components/lit-case-variables-tab.js.map +1 -1
  31. package/dist/components/lit-data-grid-tanstack.d.ts +3 -14
  32. package/dist/components/lit-data-grid-tanstack.d.ts.map +1 -1
  33. package/dist/components/lit-data-grid-tanstack.js +19 -7
  34. package/dist/components/lit-data-grid-tanstack.js.map +1 -1
  35. package/dist/components/lit-filter-builder.d.ts +67 -0
  36. package/dist/components/lit-filter-builder.d.ts.map +1 -0
  37. package/dist/components/lit-filter-builder.js +446 -0
  38. package/dist/components/lit-filter-builder.js.map +1 -0
  39. package/dist/components/lit-filter-modal.d.ts +1 -1
  40. package/dist/components/lit-filter-modal.d.ts.map +1 -1
  41. package/dist/components/lit-filter-modal.js +7 -1
  42. package/dist/components/lit-filter-modal.js.map +1 -1
  43. package/dist/components/lit-multiselect-item.d.ts.map +1 -1
  44. package/dist/components/lit-multiselect-item.js +4 -2
  45. package/dist/components/lit-multiselect-item.js.map +1 -1
  46. package/dist/components/lit-section-tab.d.ts +12 -0
  47. package/dist/components/lit-section-tab.d.ts.map +1 -1
  48. package/dist/components/lit-section-tab.js +89 -0
  49. package/dist/components/lit-section-tab.js.map +1 -1
  50. package/dist/components/lit-tabs-overview.d.ts.map +1 -1
  51. package/dist/components/lit-tabs-overview.js +10 -6
  52. package/dist/components/lit-tabs-overview.js.map +1 -1
  53. package/dist/components/modals/lit-confirm-modal.d.ts.map +1 -1
  54. package/dist/components/modals/lit-confirm-modal.js +4 -2
  55. package/dist/components/modals/lit-confirm-modal.js.map +1 -1
  56. package/dist/components/modals/lit-delete-modal.d.ts.map +1 -1
  57. package/dist/components/modals/lit-delete-modal.js +11 -7
  58. package/dist/components/modals/lit-delete-modal.js.map +1 -1
  59. package/dist/components/react-wrappers/filter-builder.d.ts +5 -0
  60. package/dist/components/react-wrappers/filter-builder.d.ts.map +1 -0
  61. package/dist/components/react-wrappers/filter-builder.js +12 -0
  62. package/dist/components/react-wrappers/filter-builder.js.map +1 -0
  63. package/dist/components/react-wrappers/index.d.ts +2 -0
  64. package/dist/components/react-wrappers/index.d.ts.map +1 -1
  65. package/dist/components/react-wrappers/index.js +2 -0
  66. package/dist/components/react-wrappers/index.js.map +1 -1
  67. package/dist/schemas/index.d.ts +2 -1
  68. package/dist/schemas/index.d.ts.map +1 -1
  69. package/dist/schemas/index.js +2 -1
  70. package/dist/schemas/index.js.map +1 -1
  71. package/dist/schemas/lit-attachments-tab-document.schema.d.ts +6 -0
  72. package/dist/schemas/lit-attachments-tab-document.schema.d.ts.map +1 -1
  73. package/dist/schemas/lit-attachments-tab-document.schema.js +6 -0
  74. package/dist/schemas/lit-attachments-tab-document.schema.js.map +1 -1
  75. package/dist/schemas/lit-attachments-tab.schema.d.ts +6 -0
  76. package/dist/schemas/lit-attachments-tab.schema.d.ts.map +1 -1
  77. package/dist/schemas/lit-case-variables-tab-cell.schema.d.ts +81 -0
  78. package/dist/schemas/lit-case-variables-tab-cell.schema.d.ts.map +1 -1
  79. package/dist/schemas/lit-case-variables-tab-cell.schema.js +60 -1
  80. package/dist/schemas/lit-case-variables-tab-cell.schema.js.map +1 -1
  81. package/dist/schemas/lit-case-variables-tab-rows.schema.d.ts +81 -0
  82. package/dist/schemas/lit-case-variables-tab-rows.schema.d.ts.map +1 -1
  83. package/dist/schemas/lit-case-variables-tab.schema.d.ts +81 -0
  84. package/dist/schemas/lit-case-variables-tab.schema.d.ts.map +1 -1
  85. package/dist/schemas/lit-data-grid-tanstack.schema.d.ts +39 -1
  86. package/dist/schemas/lit-data-grid-tanstack.schema.d.ts.map +1 -1
  87. package/dist/schemas/lit-data-grid-tanstack.schema.js +2 -1
  88. package/dist/schemas/lit-data-grid-tanstack.schema.js.map +1 -1
  89. package/dist/schemas/lit-filter-builder.schema.d.ts +67 -0
  90. package/dist/schemas/lit-filter-builder.schema.d.ts.map +1 -0
  91. package/dist/schemas/lit-filter-builder.schema.js +49 -0
  92. package/dist/schemas/lit-filter-builder.schema.js.map +1 -0
  93. package/dist/schemas/lit-section-tab-schema.d.ts +45 -0
  94. package/dist/schemas/lit-section-tab-schema.d.ts.map +1 -1
  95. package/dist/schemas/lit-section-tab-schema.js +7 -0
  96. package/dist/schemas/lit-section-tab-schema.js.map +1 -1
  97. package/dist/shared/lit-button.d.ts +3 -1
  98. package/dist/shared/lit-button.d.ts.map +1 -1
  99. package/dist/shared/lit-button.js +6 -2
  100. package/dist/shared/lit-button.js.map +1 -1
  101. package/dist/shared/lit-checkbox.d.ts +1 -0
  102. package/dist/shared/lit-checkbox.d.ts.map +1 -1
  103. package/dist/shared/lit-checkbox.js +5 -0
  104. package/dist/shared/lit-checkbox.js.map +1 -1
  105. package/dist/shared/lit-data-grid-action-buttons-popover.d.ts.map +1 -1
  106. package/dist/shared/lit-data-grid-action-buttons-popover.js +1 -0
  107. package/dist/shared/lit-data-grid-action-buttons-popover.js.map +1 -1
  108. package/dist/shared/lit-data-grid-density-popover.d.ts.map +1 -1
  109. package/dist/shared/lit-data-grid-density-popover.js +1 -0
  110. package/dist/shared/lit-data-grid-density-popover.js.map +1 -1
  111. package/dist/shared/lit-data-grid-export-popover.d.ts.map +1 -1
  112. package/dist/shared/lit-data-grid-export-popover.js +1 -0
  113. package/dist/shared/lit-data-grid-export-popover.js.map +1 -1
  114. package/dist/shared/lit-data-grid-operators-popover.d.ts +3 -3
  115. package/dist/shared/lit-data-grid-operators-popover.d.ts.map +1 -1
  116. package/dist/shared/lit-data-grid-operators-popover.js +1 -0
  117. package/dist/shared/lit-data-grid-operators-popover.js.map +1 -1
  118. package/dist/shared/lit-data-grid-row-actions.d.ts.map +1 -1
  119. package/dist/shared/lit-data-grid-row-actions.js +2 -0
  120. package/dist/shared/lit-data-grid-row-actions.js.map +1 -1
  121. package/dist/shared/lit-date-picker.d.ts +1 -1
  122. package/dist/shared/lit-date-picker.d.ts.map +1 -1
  123. package/dist/shared/lit-date-picker.js +2 -0
  124. package/dist/shared/lit-date-picker.js.map +1 -1
  125. package/dist/shared/lit-icon-button.d.ts +7 -3
  126. package/dist/shared/lit-icon-button.d.ts.map +1 -1
  127. package/dist/shared/lit-icon-button.js +6 -2
  128. package/dist/shared/lit-icon-button.js.map +1 -1
  129. package/dist/shared/lit-input.d.ts +3 -1
  130. package/dist/shared/lit-input.d.ts.map +1 -1
  131. package/dist/shared/lit-input.js +35 -28
  132. package/dist/shared/lit-input.js.map +1 -1
  133. package/dist/shared/lit-modal-body.js +1 -1
  134. package/dist/shared/lit-modal-footer.js +1 -1
  135. package/dist/shared/lit-modal-header.d.ts.map +1 -1
  136. package/dist/shared/lit-modal-header.js +1 -2
  137. package/dist/shared/lit-modal-header.js.map +1 -1
  138. package/dist/shared/lit-progress-bar.d.ts +2 -0
  139. package/dist/shared/lit-progress-bar.d.ts.map +1 -1
  140. package/dist/shared/lit-progress-bar.js +57 -7
  141. package/dist/shared/lit-progress-bar.js.map +1 -1
  142. package/dist/shared/lit-responsive-button.d.ts +17 -2
  143. package/dist/shared/lit-responsive-button.d.ts.map +1 -1
  144. package/dist/shared/lit-responsive-button.js +8 -0
  145. package/dist/shared/lit-responsive-button.js.map +1 -1
  146. package/dist/shared/lit-select-field.d.ts.map +1 -1
  147. package/dist/shared/lit-select-field.js +1 -2
  148. package/dist/shared/lit-select-field.js.map +1 -1
  149. package/dist/shared/lit-select.d.ts +5 -1
  150. package/dist/shared/lit-select.d.ts.map +1 -1
  151. package/dist/shared/lit-select.js +218 -6
  152. package/dist/shared/lit-select.js.map +1 -1
  153. package/dist/shared/lit-text-field.d.ts +2 -0
  154. package/dist/shared/lit-text-field.d.ts.map +1 -1
  155. package/dist/shared/lit-text-field.js +27 -10
  156. package/dist/shared/lit-text-field.js.map +1 -1
  157. package/dist/shared/styles/button-shared-styles.d.ts.map +1 -1
  158. package/dist/shared/styles/button-shared-styles.js +321 -28
  159. package/dist/shared/styles/button-shared-styles.js.map +1 -1
  160. package/dist/utils/getOperatorByType.d.ts +5 -5
  161. package/dist/utils/getOperatorByType.d.ts.map +1 -1
  162. package/dist/utils/getOperatorByType.js +5 -1
  163. package/dist/utils/getOperatorByType.js.map +1 -1
  164. package/package.json +5 -2
@@ -10,6 +10,7 @@ import { styleMap } from 'lit/directives/style-map.js';
10
10
  import { customElement, property, state } from 'lit/decorators.js';
11
11
  import Sortable from 'sortablejs';
12
12
  import { repeat } from 'lit/directives/repeat.js';
13
+ import { Pane } from 'tweakpane';
13
14
  // components
14
15
  import '../shared/lit-icon.js';
15
16
  import '../shared/lit-button.js';
@@ -28,6 +29,7 @@ import { formatCurrency, formatDecimal } from '../utils/formatNumber.js';
28
29
  import { setLocale } from '../utils/localization.js';
29
30
  import { msg } from '@lit/localize';
30
31
  import { isEqual } from 'lodash';
32
+ import { getOperatorsByColumnType, getDefaultOperator, } from '../utils/getOperatorByType.js';
31
33
  let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
32
34
  constructor() {
33
35
  super(...arguments);
@@ -46,7 +48,10 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
46
48
  this.isMobile = window.innerWidth <= 600;
47
49
  this._resizeListener = this.handleResize.bind(this);
48
50
  this.sortableInstances = [];
51
+ this.settingsPanes = new Map();
49
52
  this.sortableGroupId = `group-${Math.random().toString(36).substring(2, 9)}`;
53
+ this.activeSettingsCell = null;
54
+ this.settingsPopperOpen = false;
50
55
  this.backgroundColorOptions = [
51
56
  {
52
57
  backgroundColor: 'transparent',
@@ -73,78 +78,82 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
73
78
  border: '1px solid var(--color-primary-dark)',
74
79
  },
75
80
  ];
81
+ this.valueColorOptions = [
82
+ {
83
+ color: 'var(--text-primary)',
84
+ },
85
+ {
86
+ color: 'var(--color-success-main)',
87
+ },
88
+ {
89
+ color: 'var(--color-error-main)',
90
+ },
91
+ {
92
+ color: 'var(--color-warning-main)',
93
+ },
94
+ {
95
+ color: 'var(--color-info-main)',
96
+ },
97
+ {
98
+ color: 'var(--color-primary-main)',
99
+ },
100
+ ];
76
101
  this.language = 'cs';
77
102
  this.BREAKPOINTS = ['xs', 'sm', 'md', 'lg', 'xl'];
103
+ this.closeSettingsPopper = () => {
104
+ // Clean up any existing tweakpanes before closing
105
+ this.destroySettingsPanes();
106
+ this.settingsPopperOpen = false;
107
+ this.activeSettingsCell = null;
108
+ };
78
109
  this.handleSettingsChanged = (newRows) => {
79
110
  this.onSettingsChanged?.(newRows);
80
111
  };
112
+ this.addCustomEmptyCell = () => {
113
+ // Generate a unique field name for the custom cell
114
+ const customCellCount = this.rows.filter((cell) => cell.field.startsWith('custom_cell_')).length;
115
+ const fieldName = `custom_cell_${customCellCount + 1}`;
116
+ // Create a new empty custom cell (without tooltip, headerName, or value)
117
+ const newCell = {
118
+ field: fieldName,
119
+ type: 'string',
120
+ size: { xs: 4, sm: 2, md: 1, lg: 1, xl: 1 },
121
+ };
122
+ const newRows = [...this.rows, newCell];
123
+ this.rows = newRows;
124
+ this.handleSettingsChanged(newRows);
125
+ // Automatically open settings for the new cell to allow user to customize it
126
+ setTimeout(() => {
127
+ this.toggleSettingsPane(newCell);
128
+ }, 100);
129
+ };
81
130
  this.getHeaderActions = (cell) => {
82
- const activeSize = cell.size?.lg ?? 1;
83
131
  return html `<div class="header-buttons">
84
132
  ${this.enableSettings
85
133
  ? html `
86
- <perf-tooltip placement="top">
87
- <lit-icon slot="trigger" icon="cog" size="1rem"></lit-icon>
88
- <div slot="tooltip">
89
- <div class="settings-buttons" style="justify-content: space-between">
90
- ${this.gridVariables
91
- ? html `<div></div>`
92
- : html `
93
- <div>
94
- ${[1, 2, 3, 4].map((size) => html `
95
- <span
96
- @click=${() => this.setCellSize(size, cell)}
97
- class="size-button ${activeSize === size
98
- ? 'size-button--active'
99
- : ''}"
100
- >
101
- ${size}
102
- </span>
103
- `)}
104
- </div>
105
- `}
106
-
107
- <lit-icon
108
- icon="trash"
109
- size="1rem"
110
- style="cursor: pointer"
111
- @click=${() => this.removeCellFromRows(cell.field)}
112
- ></lit-icon>
113
- </div>
114
- <div class="color-label">${msg('Barva pozadí')}:</div>
115
- <div class="settings-buttons">
116
- ${this.backgroundColorOptions.map((option) => html `
117
- <div>
118
- <div
119
- @click=${() => this.setCellStyle({
120
- backgroundColor: option.backgroundColor,
121
- borderRadius: '8px',
122
- border: option.border,
123
- }, cell)}
124
- class="cell-background"
125
- style="background-color: ${option.backgroundColor}; border: ${option.border}"
126
- ></div>
127
- <div
128
- class="${this.isActiveBackground(cell, option.backgroundColor)
129
- ? 'cell-background--active'
130
- : ''}"
131
- ></div>
132
- </div>
133
- `)}
134
- </div>
135
- <div class="color-label">${msg('Tučné písmo')}:</div>
136
- <div class="settings-buttons">
137
- <span
138
- class="bold-toggle ${cell?.valueStyle?.fontWeight === 'bold'
139
- ? 'bold-toggle--active'
140
- : ''}"
141
- @click=${() => this.setFontWeight(cell)}
142
- >
143
- B
144
- </span>
145
- </div>
146
- </div>
147
- </perf-tooltip>
134
+ <div style="position: relative;">
135
+ <lit-icon
136
+ icon="cog"
137
+ size="1rem"
138
+ style="cursor: pointer"
139
+ @click=${() => this.toggleSettingsPane(cell)}
140
+ id="settings-trigger-${cell.field}"
141
+ ></lit-icon>
142
+
143
+ ${this.activeSettingsCell?.field === cell.field
144
+ ? html `
145
+ <simple-popper
146
+ .showing=${this.settingsPopperOpen}
147
+ .placement=${'bottom-middle'}
148
+ .manualOpening=${true}
149
+ .maxWidthAsTarget=${false}
150
+ .onClose=${this.closeSettingsPopper}
151
+ >
152
+ ${this.renderSettingsContent()}
153
+ </simple-popper>
154
+ `
155
+ : ''}
156
+ </div>
148
157
 
149
158
  <div class="drag-handle">
150
159
  <lit-icon icon="hamburger" size="1rem"></lit-icon>
@@ -178,6 +187,18 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
178
187
  ${this.getHeaderLabel(cell)} ${this.getHeaderActions(cell)}
179
188
  </div>`;
180
189
  };
190
+ this.handleButtonClick = (cell) => {
191
+ // First try the original buttonFn if it exists and is a function
192
+ if (cell.buttonFn && typeof cell.buttonFn === 'function') {
193
+ cell.buttonFn();
194
+ return;
195
+ }
196
+ // Otherwise use the href functionality like links
197
+ const url = this.getLinkUrl(cell);
198
+ if (url) {
199
+ window.open(url, '_blank');
200
+ }
201
+ };
181
202
  this.getCellButton = (cell) => {
182
203
  return html `
183
204
  <div style="display: flex; justify-content: space-between">
@@ -185,25 +206,26 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
185
206
  style="flex-grow: 1; margin-right: 0.5rem"
186
207
  .fullWidth="${cell.buttonFullWidth}"
187
208
  variant="${cell.buttonVariant || 'contained'}"
209
+ color="${cell.buttonColor || 'primary'}"
188
210
  label="${cell?.headerName}"
189
- @click=${cell?.buttonFn}
211
+ @click=${() => this.handleButtonClick(cell)}
190
212
  ></lit-button>
191
213
  ${this.getHeaderActions(cell)}
192
214
  </div>
193
215
  `;
194
216
  };
195
217
  this.getCellLink = (cell) => {
218
+ const linkUrl = this.getLinkUrl(cell);
219
+ const displayText = cell?.value || linkUrl || '';
196
220
  return html `<div>${this.getHeader(cell)}</div>
197
- <a class="link" href=${cell?.value ? cell.value : ''} target="_blank"
198
- >${cell?.value ? cell.value : ''}
199
- </a> `;
221
+ <a class="link" href=${linkUrl} target="_blank">${displayText} </a> `;
200
222
  };
201
223
  this.getCellValue = (cell) => {
202
224
  const rawValue = cell?.[`value_${this.userLang}`] || cell?.value || '';
203
225
  const value = typeof rawValue === 'string' ? rawValue : String(rawValue ?? '');
204
226
  return html `<div>${this.getHeader(cell)}</div>
205
227
  <div
206
- style="${cell?.valueStyle ? styleMap(cell?.valueStyle) : ''}"
228
+ style="${styleMap(this.computeValueStyles(cell))}"
207
229
  class="process-data-value"
208
230
  >
209
231
  ${unsafeHTML(value)}
@@ -212,7 +234,7 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
212
234
  this.getCellDate = (cell) => {
213
235
  return html `<div>${this.getHeader(cell)}</div>
214
236
  <div
215
- style="${cell?.valueStyle ? styleMap(cell?.valueStyle) : ''}"
237
+ style="${styleMap(this.computeValueStyles(cell))}"
216
238
  class="process-data-value"
217
239
  >
218
240
  ${cell?.value
@@ -223,7 +245,7 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
223
245
  this.getCellCurrency = (cell) => {
224
246
  return html `<div>${this.getHeader(cell)}</div>
225
247
  <div
226
- style="${cell?.valueStyle ? styleMap(cell?.valueStyle) : ''}"
248
+ style="${styleMap(this.computeValueStyles(cell))}"
227
249
  class="process-data-value"
228
250
  >
229
251
  ${cell?.value
@@ -238,7 +260,7 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
238
260
  this.getCellNumber = (cell) => {
239
261
  return html `<div>${this.getHeader(cell)}</div>
240
262
  <div
241
- style="${cell?.valueStyle ? styleMap(cell?.valueStyle) : ''}"
263
+ style="${styleMap(this.computeValueStyles(cell))}"
242
264
  class="process-data-value"
243
265
  >
244
266
  ${cell?.value
@@ -252,12 +274,19 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
252
274
  </div> `;
253
275
  };
254
276
  this.getCellProgress = (cell) => {
277
+ // Convert decimal value (0.0-1.0) to percentage (0-100) for lit-progress-bar
278
+ const progressValue = typeof cell?.value === 'number' ? cell.value * 100 : 0;
255
279
  return html `<div>${this.getHeader(cell)}</div>
256
280
  <div
257
- style="${cell?.valueStyle ? styleMap(cell?.valueStyle) : ''}"
281
+ style="${styleMap(this.computeValueStyles(cell))}"
258
282
  class="process-data-value"
259
283
  >
260
- <lit-progress-bar .progress="${cell?.value}"></lit-progress-bar>
284
+ <lit-progress-bar
285
+ .progress="${progressValue}"
286
+ .color="${cell.progressColor || 'primary'}"
287
+ label=""
288
+ style="width: 100%;"
289
+ ></lit-progress-bar>
261
290
  </div> `;
262
291
  };
263
292
  this.getInlineCellValue = (cell) => {
@@ -289,6 +318,10 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
289
318
  ? formatDate(cell.value, this.userLang || 'cs', !!this.dateFormat, this.dateFormat)
290
319
  : '';
291
320
  break;
321
+ case 'progress':
322
+ // For progress, show percentage value
323
+ value = cell?.value ? `${Math.round(cell.value * 100)}%` : '0%';
324
+ break;
292
325
  default:
293
326
  value = typeof rawValue === 'string' ? rawValue : String(rawValue ?? '');
294
327
  }
@@ -296,7 +329,7 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
296
329
  <div style="display: flex;align-items: center; justify-content: end; gap: 0.5rem;">
297
330
  <div
298
331
  style="${styleMap({
299
- ...(cell.cellStyle || {}),
332
+ ...this.computeCellStyles(cell),
300
333
  width: 'fit-content',
301
334
  display: 'flex',
302
335
  alignItems: 'center',
@@ -305,10 +338,12 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
305
338
  padding: '0.375rem',
306
339
  })}"
307
340
  >
308
- <div style="display: flex;align-items: center; justify-content: end; gap: 0.5rem; flex-direction: row">
341
+ <div
342
+ style="display: flex;align-items: center; justify-content: end; gap: 0.5rem; flex-direction: row"
343
+ >
309
344
  <div>${this.getHeaderLabel(cell)}</div>
310
345
  <div
311
- style="${cell?.valueStyle ? styleMap(cell?.valueStyle) : ''}"
346
+ style="${styleMap(this.computeValueStyles(cell))}"
312
347
  class="process-data-value"
313
348
  >
314
349
  ${value}
@@ -320,6 +355,105 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
320
355
  `;
321
356
  };
322
357
  }
358
+ createCellSettingsConfig(cell) {
359
+ return {
360
+ size: cell.size?.lg ?? 1,
361
+ mobileSize: cell.size?.xs ?? 4,
362
+ cellVariant: cell.cellVariant || 'default',
363
+ cellCustomStyles: cell.cellCustomStyles || false,
364
+ valueVariant: cell.valueVariant || 'default',
365
+ valueCustomStyles: cell.valueCustomStyles || false,
366
+ fontWeight: cell.valueStyle?.fontWeight === 'bold',
367
+ valueColor: this.getValueColorIndex(cell),
368
+ cellType: cell.type || 'string',
369
+ // Cell content properties
370
+ headerName: cell.headerName || '',
371
+ cellValue: cell.value || '',
372
+ // Cell type specific properties
373
+ href: cell.href || '',
374
+ linkType: cell.linkType || 'custom',
375
+ linkVariable: cell.linkVariable || '',
376
+ dynamicLink: cell.dynamicLink || '',
377
+ numberOfDecimal: cell.numberOfDecimal ?? 2,
378
+ progressColor: cell.progressColor || 'primary',
379
+ buttonVariant: cell.buttonVariant || 'contained',
380
+ buttonColor: cell.buttonColor || 'primary',
381
+ buttonFullWidth: cell.buttonFullWidth ?? false,
382
+ currencyType: cell.currencyType || 'CZK',
383
+ customCSS: JSON.stringify(cell.cellStyle || {}),
384
+ // Conditional formatting - simplified structure
385
+ conditionEnabled: !!cell.conditionalFormatting?.enabled,
386
+ conditionVariable: cell.conditionalFormatting?.variable ?? '',
387
+ conditionOperator: cell.conditionalFormatting?.operator ??
388
+ this.getDefaultOperatorForCell(cell),
389
+ conditionValue: cell.conditionalFormatting?.value ?? '',
390
+ conditionColor: this.getConditionColorIndex(cell),
391
+ // Conditional hide cell settings
392
+ hideConditionEnabled: !!cell.hideCondition?.enabled,
393
+ hideConditionVariable: cell.hideCondition?.variable ?? '',
394
+ hideConditionOperator: cell.hideCondition?.operator ?? this.getDefaultOperatorForCell(cell),
395
+ hideConditionValue: cell.hideCondition?.value ?? '',
396
+ };
397
+ }
398
+ getValueColorIndex(cell) {
399
+ const valueColor = cell.valueStyle?.color;
400
+ if (!valueColor || valueColor === 'transparent')
401
+ return 0;
402
+ const index = this.valueColorOptions.findIndex((option) => option.color === valueColor);
403
+ return index >= 0 ? index : 0;
404
+ }
405
+ getConditionColorIndex(cell) {
406
+ const conditionBg = cell.conditionalFormatting?.backgroundColor;
407
+ if (!conditionBg || conditionBg === 'transparent')
408
+ return 0;
409
+ const index = this.backgroundColorOptions.findIndex((option) => option.backgroundColor === conditionBg);
410
+ return index >= 0 ? index : 0;
411
+ }
412
+ getOperatorOptionsForCell(cell) {
413
+ let cellType = 'string'; // default type
414
+ // Map cell types to Type enum
415
+ switch (cell.type) {
416
+ case 'number':
417
+ case 'currency':
418
+ case 'progress':
419
+ cellType = 'number';
420
+ break;
421
+ case 'date':
422
+ cellType = 'date';
423
+ break;
424
+ case 'string':
425
+ case 'button':
426
+ case 'link':
427
+ default:
428
+ cellType = 'string';
429
+ break;
430
+ }
431
+ return getOperatorsByColumnType(cellType).map((op) => ({
432
+ text: op.label,
433
+ value: op.value,
434
+ }));
435
+ }
436
+ getDefaultOperatorForCell(cell) {
437
+ let cellType = 'string'; // default type
438
+ // Map cell types to Type enum
439
+ switch (cell.type) {
440
+ case 'number':
441
+ case 'currency':
442
+ case 'progress':
443
+ cellType = 'number';
444
+ break;
445
+ case 'date':
446
+ cellType = 'date';
447
+ break;
448
+ case 'string':
449
+ case 'button':
450
+ case 'link':
451
+ default:
452
+ cellType = 'string';
453
+ break;
454
+ }
455
+ return getDefaultOperator(cellType);
456
+ }
323
457
  getBreakpoint() {
324
458
  const width = window.innerWidth;
325
459
  if (width >= 1920)
@@ -355,6 +489,7 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
355
489
  }
356
490
  disconnectedCallback() {
357
491
  this.destroySortables();
492
+ this.destroySettingsPanes();
358
493
  window.removeEventListener('resize', this._resizeListener); // Remove listener
359
494
  super.disconnectedCallback();
360
495
  }
@@ -363,8 +498,36 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
363
498
  this.initSortable();
364
499
  }
365
500
  }
501
+ loadTweakpaneCSS() {
502
+ // Check if CSS is already loaded
503
+ if (document.querySelector('link[href*="tweakpane"]')) {
504
+ return;
505
+ }
506
+ // Create link element for Tweakpane CSS
507
+ const link = document.createElement('link');
508
+ link.rel = 'stylesheet';
509
+ link.href = 'https://unpkg.com/tweakpane@4.0.5/dist/tweakpane.css';
510
+ document.head.appendChild(link);
511
+ // Add some basic custom styles for tooltip usage
512
+ const style = document.createElement('style');
513
+ style.textContent = `
514
+ .tp-dfwv {
515
+ min-width: 240px !important;
516
+ }
517
+ .tp-rotv {
518
+ font-size: 12px !important;
519
+ }
520
+ .tp-lblv_l {
521
+ font-size: 11px !important;
522
+ }
523
+ `;
524
+ document.head.appendChild(style);
525
+ }
366
526
  setFontWeight(cell) {
367
527
  const isBold = cell.valueStyle?.fontWeight === 'bold';
528
+ // Enable custom styles mode and set font weight
529
+ cell.valueCustomStyles = true;
530
+ cell.valueVariant = 'default';
368
531
  cell.valueStyle = {
369
532
  ...(cell.valueStyle || {}),
370
533
  fontWeight: isBold ? '500' : 'bold',
@@ -372,17 +535,1064 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
372
535
  this.rows = [...this.rows];
373
536
  this.handleSettingsChanged(this.rows);
374
537
  }
538
+ getAvailableVariables(excludeField) {
539
+ const variables = [];
540
+ // Add variables from current rows (excluding the current cell)
541
+ this.rows.forEach((cell) => {
542
+ if (cell.field !== excludeField) {
543
+ variables.push({
544
+ text: cell.headerName || cell.field,
545
+ value: cell.field,
546
+ });
547
+ }
548
+ });
549
+ // Add variables from data object (that are not in current rows)
550
+ const existingFields = this.rows.map((cell) => cell.field);
551
+ Object.keys(this.data || {}).forEach((key) => {
552
+ if (key !== excludeField && !existingFields.includes(key)) {
553
+ const item = this.data[key];
554
+ const lang = this.userLang || 'cs';
555
+ const name = item?.[`tvar_name_${lang}`] || item?.tvar_name_cs || key;
556
+ variables.push({
557
+ text: name,
558
+ value: key,
559
+ });
560
+ }
561
+ });
562
+ return variables.sort((a, b) => a.text.localeCompare(b.text));
563
+ }
564
+ getAllAvailableVariables() {
565
+ const variables = [];
566
+ // Add variables from current rows (including all cells)
567
+ this.rows.forEach((cell) => {
568
+ variables.push({
569
+ text: cell.headerName || cell.field,
570
+ value: cell.field,
571
+ });
572
+ });
573
+ // Add variables from data object (that are not in current rows)
574
+ const existingFields = this.rows.map((cell) => cell.field);
575
+ Object.keys(this.data || {}).forEach((key) => {
576
+ if (!existingFields.includes(key)) {
577
+ const item = this.data[key];
578
+ const lang = this.userLang || 'cs';
579
+ const name = item?.[`tvar_name_${lang}`] || item?.tvar_name_cs || key;
580
+ variables.push({
581
+ text: name,
582
+ value: key,
583
+ });
584
+ }
585
+ });
586
+ return variables.sort((a, b) => a.text.localeCompare(b.text));
587
+ }
588
+ setConditionalFormatting(cell, property, value) {
589
+ // Initialize conditional formatting if not exists
590
+ if (!cell.conditionalFormatting) {
591
+ cell.conditionalFormatting = {
592
+ // enabled: false,
593
+ // variable: '',
594
+ // operator: 'equals',
595
+ // value: '',
596
+ // backgroundColor: 'transparent',
597
+ };
598
+ }
599
+ // Set the property
600
+ cell.conditionalFormatting[property] = value;
601
+ this.rows = [...this.rows];
602
+ this.handleSettingsChanged(this.rows);
603
+ }
375
604
  setCellStyle(style, cell) {
376
605
  cell.cellStyle = style;
377
606
  this.rows = [...this.rows];
378
607
  this.handleSettingsChanged(this.rows);
379
608
  }
609
+ setCellVariant(variant, cell) {
610
+ cell.cellVariant = variant;
611
+ // If setting a semantic variant, disable custom styles
612
+ if (variant !== 'default') {
613
+ cell.cellCustomStyles = false;
614
+ }
615
+ this.rows = [...this.rows];
616
+ this.handleSettingsChanged(this.rows);
617
+ }
618
+ setValueVariant(variant, cell) {
619
+ cell.valueVariant = variant;
620
+ // If setting a semantic variant, disable custom styles
621
+ if (variant !== 'default') {
622
+ cell.valueCustomStyles = false;
623
+ }
624
+ this.rows = [...this.rows];
625
+ this.handleSettingsChanged(this.rows);
626
+ }
627
+ enableCellCustomStyles(cell) {
628
+ cell.cellCustomStyles = true;
629
+ cell.cellVariant = 'default';
630
+ this.rows = [...this.rows];
631
+ this.handleSettingsChanged(this.rows);
632
+ }
633
+ enableValueCustomStyles(cell) {
634
+ cell.valueCustomStyles = true;
635
+ cell.valueVariant = 'default';
636
+ this.rows = [...this.rows];
637
+ this.handleSettingsChanged(this.rows);
638
+ }
380
639
  destroySortables() {
381
640
  this.sortableInstances.forEach((instance) => {
382
641
  instance.destroy();
383
642
  });
384
643
  this.sortableInstances = [];
385
644
  }
645
+ destroySettingsPanes() {
646
+ this.settingsPanes.forEach((pane, field) => {
647
+ try {
648
+ pane.dispose();
649
+ }
650
+ catch (error) {
651
+ console.error(`Error disposing pane for ${field}:`, error);
652
+ }
653
+ });
654
+ this.settingsPanes.clear();
655
+ // Remove any floating tooltip containers (legacy cleanup)
656
+ document.querySelectorAll('.tweakpane-floating-tooltip').forEach((el) => {
657
+ el.remove();
658
+ });
659
+ // Clean up any leftover tweakpane containers in document
660
+ document.querySelectorAll('[id^="tweakpane-"]').forEach((el) => {
661
+ const parentContainer = el.closest('.tweakpane-container');
662
+ if (parentContainer) {
663
+ parentContainer.remove();
664
+ }
665
+ });
666
+ }
667
+ toggleSettingsPane(cell) {
668
+ // If clicking the same cell, toggle the popper
669
+ if (this.activeSettingsCell?.field === cell.field) {
670
+ this.settingsPopperOpen = !this.settingsPopperOpen;
671
+ if (!this.settingsPopperOpen) {
672
+ this.activeSettingsCell = null;
673
+ }
674
+ }
675
+ else {
676
+ // Different cell, show popper for this cell
677
+ this.activeSettingsCell = cell;
678
+ this.settingsPopperOpen = true;
679
+ }
680
+ }
681
+ renderSettingsContent() {
682
+ if (!this.activeSettingsCell)
683
+ return null;
684
+ const cell = this.activeSettingsCell;
685
+ return html `
686
+ <div class="tweakpane-container" @click=${(e) => e.stopPropagation()}>
687
+ <div id="tweakpane-${cell.field}"></div>
688
+ </div>
689
+ `;
690
+ }
691
+ updated(changedProperties) {
692
+ super.updated(changedProperties);
693
+ // Initialize tweakpane when activeSettingsCell changes and popper is open
694
+ if (changedProperties.has('activeSettingsCell') ||
695
+ changedProperties.has('settingsPopperOpen')) {
696
+ if (this.activeSettingsCell && this.settingsPopperOpen) {
697
+ // Use multiple requestAnimationFrame calls and retry logic for better reliability
698
+ requestAnimationFrame(() => {
699
+ requestAnimationFrame(() => {
700
+ this.initializeTweakpaneWithRetry(this.activeSettingsCell);
701
+ });
702
+ });
703
+ }
704
+ }
705
+ }
706
+ initializeTweakpaneWithRetry(cell, attempt = 1) {
707
+ // Clean up any existing pane for this cell first
708
+ const existingPane = this.settingsPanes.get(cell.field);
709
+ if (existingPane) {
710
+ existingPane.dispose();
711
+ this.settingsPanes.delete(cell.field);
712
+ }
713
+ const maxAttempts = 10;
714
+ const selector = `#tweakpane-${cell.field}`;
715
+ const container = document.querySelector(selector) || this.shadowRoot?.querySelector(selector);
716
+ if (container) {
717
+ this.initializeTweakpane(cell, 0);
718
+ }
719
+ else if (attempt < maxAttempts) {
720
+ setTimeout(() => {
721
+ // Check if we're still supposed to be showing this cell
722
+ if (this.activeSettingsCell?.field === cell.field && this.settingsPopperOpen) {
723
+ this.initializeTweakpaneWithRetry(cell, attempt + 1);
724
+ }
725
+ }, 50);
726
+ }
727
+ else {
728
+ console.warn(`Failed to find tweakpane container for ${cell.field} after ${maxAttempts} attempts`);
729
+ }
730
+ }
731
+ initializeTweakpane(cell, retryCount = 0) {
732
+ // Load Tweakpane CSS
733
+ this.loadTweakpaneCSS();
734
+ // Get the container from simple-popper (rendered in document)
735
+ const selector = `#tweakpane-${cell.field}`;
736
+ // simple-popper renders content to document body, so check there first
737
+ const container = document.querySelector(selector) || this.shadowRoot?.querySelector(selector);
738
+ if (!container) {
739
+ if (retryCount < 3) {
740
+ console.warn(`Tweakpane container not found, retrying... (${retryCount + 1}/3):`, `#tweakpane-${cell.field}`);
741
+ setTimeout(() => {
742
+ this.initializeTweakpane(cell, retryCount + 1);
743
+ }, 100);
744
+ return;
745
+ }
746
+ else {
747
+ console.error('Tweakpane container not found after 3 retries:', `#tweakpane-${cell.field}`);
748
+ return;
749
+ }
750
+ }
751
+ // Clear any existing pane for this cell
752
+ const existingPane = this.settingsPanes.get(cell.field);
753
+ if (existingPane) {
754
+ existingPane.dispose();
755
+ this.settingsPanes.delete(cell.field);
756
+ }
757
+ // Create Tweakpane in the container
758
+ const pane = new Pane({
759
+ container: container,
760
+ title: `${cell.headerName || cell.field}`,
761
+ });
762
+ const config = this.createCellSettingsConfig(cell);
763
+ // Add size controls for desktop and mobile (only if not in grid variables mode)
764
+ if (!this.gridVariables) {
765
+ // Desktop size input
766
+ const desktopSizeInput = pane.addBinding(config, 'size', {
767
+ view: 'list',
768
+ label: 'Desktop Size',
769
+ options: [
770
+ { text: '1 Column', value: 1 },
771
+ { text: '2 Columns', value: 2 },
772
+ { text: '3 Columns', value: 3 },
773
+ { text: '4 Columns', value: 4 },
774
+ ],
775
+ });
776
+ desktopSizeInput.on('change', (ev) => {
777
+ this.setCellSize(ev.value, cell, 'lg');
778
+ });
779
+ // Mobile size input
780
+ const mobileSizeInput = pane.addBinding(config, 'mobileSize', {
781
+ view: 'list',
782
+ label: 'Mobile Size',
783
+ options: [
784
+ { text: '1 Column', value: 1 },
785
+ { text: '2 Columns', value: 2 },
786
+ { text: '3 Columns', value: 3 },
787
+ { text: '4 Columns', value: 4 },
788
+ ],
789
+ });
790
+ mobileSizeInput.on('change', (ev) => {
791
+ this.setCellSize(ev.value, cell, 'xs');
792
+ });
793
+ }
794
+ // Add cell type control - at the top
795
+ const cellTypeInput = pane.addBinding(config, 'cellType', {
796
+ view: 'list',
797
+ label: 'Cell Type',
798
+ options: [
799
+ { text: 'String', value: 'string' },
800
+ { text: 'Button', value: 'button' },
801
+ { text: 'Link', value: 'link' },
802
+ { text: 'Date', value: 'date' },
803
+ { text: 'Currency', value: 'currency' },
804
+ { text: 'Progress', value: 'progress' },
805
+ { text: 'Number', value: 'number' },
806
+ ],
807
+ });
808
+ cellTypeInput.on('change', (ev) => {
809
+ this.setCellType(cell, ev.value);
810
+ });
811
+ // Add header name and value controls (only for custom cells)
812
+ const isCustomCell = cell.field.startsWith('custom_cell_');
813
+ if (isCustomCell) {
814
+ const headerNameInput = pane.addBinding(config, 'headerName', {
815
+ label: 'Cell Header',
816
+ });
817
+ headerNameInput.on('change', (ev) => {
818
+ this.setCellHeaderName(cell, ev.value);
819
+ });
820
+ // Add cell value control for custom cells
821
+ const cellValueInput = pane.addBinding(config, 'cellValue', {
822
+ label: 'Cell Value',
823
+ multiline: cell.type === 'string',
824
+ });
825
+ cellValueInput.on('change', (ev) => {
826
+ this.setCellValue(cell, ev.value);
827
+ });
828
+ }
829
+ // Add cell variant control - common for all types
830
+ const cellVariantOptions = [
831
+ { text: 'Default', value: 'default' },
832
+ { text: 'Primary', value: 'primary' },
833
+ { text: 'Success', value: 'success' },
834
+ { text: 'Warning', value: 'warning' },
835
+ { text: 'Error', value: 'error' },
836
+ { text: 'Info', value: 'info' },
837
+ { text: 'Custom', value: 'custom' },
838
+ ];
839
+ const cellVariantInput = pane.addBinding(config, 'cellVariant', {
840
+ view: 'list',
841
+ label: 'Cell Style',
842
+ options: cellVariantOptions,
843
+ });
844
+ // Add CSS input for custom styles (always present but controlled by visibility)
845
+ const cssInput = pane.addBinding(config, 'customCSS', {
846
+ label: 'Cell CSS',
847
+ multiline: true,
848
+ rows: 4,
849
+ });
850
+ cssInput.on('change', (ev) => {
851
+ try {
852
+ const cssObject = JSON.parse(ev.value || '{}');
853
+ this.setCellStyle(cssObject, cell);
854
+ }
855
+ catch (error) {
856
+ console.error('Invalid JSON for custom CSS:', error);
857
+ }
858
+ });
859
+ const showCssInput = () => {
860
+ if (cssInput.element) {
861
+ cssInput.element.style.display = '';
862
+ }
863
+ };
864
+ const hideCssInput = () => {
865
+ if (cssInput.element) {
866
+ cssInput.element.style.display = 'none';
867
+ }
868
+ };
869
+ // Set initial visibility based on whether custom style is selected
870
+ if (config.cellCustomStyles) {
871
+ showCssInput();
872
+ }
873
+ else {
874
+ hideCssInput();
875
+ }
876
+ cellVariantInput.on('change', (ev) => {
877
+ if (ev.value === 'custom') {
878
+ this.enableCellCustomStyles(cell);
879
+ showCssInput();
880
+ }
881
+ else {
882
+ this.setCellVariant(ev.value, cell);
883
+ hideCssInput();
884
+ }
885
+ });
886
+ // Add cell type-specific controls
887
+ this.addCellTypeSpecificControls(pane, config, cell);
888
+ // Add conditional formatting section
889
+ const conditionFolder = pane.addFolder({
890
+ title: 'Conditional Cell Formatting',
891
+ expanded: false,
892
+ });
893
+ // Enable/disable conditional formatting
894
+ const conditionEnabledInput = conditionFolder.addBinding(config, 'conditionEnabled', {
895
+ label: 'Enable Conditions',
896
+ });
897
+ conditionEnabledInput.on('change', (ev) => {
898
+ this.setConditionalFormatting(cell, 'enabled', ev.value);
899
+ });
900
+ // Variable selector - compare against variables from grid (including current cell)
901
+ const variableOptions = this.getAllAvailableVariables();
902
+ if (variableOptions.length > 0) {
903
+ // Set default variable to current cell's field if not already set
904
+ if (!config.conditionVariable) {
905
+ config.conditionVariable = cell.field;
906
+ this.setConditionalFormatting(cell, 'variable', cell.field);
907
+ }
908
+ const conditionVariableInput = conditionFolder.addBinding(config, 'conditionVariable', {
909
+ view: 'list',
910
+ label: 'Variable',
911
+ options: variableOptions,
912
+ });
913
+ conditionVariableInput.on('change', (ev) => {
914
+ this.setConditionalFormatting(cell, 'variable', ev.value);
915
+ });
916
+ }
917
+ // Condition operator - use operators based on cell type
918
+ const operatorOptions = this.getOperatorOptionsForCell(cell);
919
+ const operatorInput = conditionFolder.addBinding(config, 'conditionOperator', {
920
+ view: 'list',
921
+ label: 'Operator',
922
+ options: operatorOptions,
923
+ });
924
+ operatorInput.on('change', (ev) => {
925
+ this.setConditionalFormatting(cell, 'operator', ev.value);
926
+ });
927
+ // Condition value - text input for comparison value
928
+ const conditionValueInput = conditionFolder.addBinding(config, 'conditionValue', {
929
+ label: 'Value',
930
+ });
931
+ conditionValueInput.on('change', (ev) => {
932
+ this.setConditionalFormatting(cell, 'value', ev.value);
933
+ });
934
+ // Condition background color
935
+ const conditionColorInput = conditionFolder.addBinding(config, 'conditionColor', {
936
+ view: 'list',
937
+ label: 'Cell Style',
938
+ options: this.backgroundColorOptions.map((option, index) => ({
939
+ text: this.getBackgroundColorName(option.backgroundColor),
940
+ value: index,
941
+ })),
942
+ });
943
+ conditionColorInput.on('change', (ev) => {
944
+ const selectedOption = this.backgroundColorOptions[ev.value];
945
+ this.setConditionalFormatting(cell, 'backgroundColor', selectedOption.backgroundColor);
946
+ });
947
+ // input for value color
948
+ const conditionValueColorInput = conditionFolder.addBinding(config, 'valueColor', {
949
+ view: 'list',
950
+ label: 'Value Color',
951
+ options: this.valueColorOptions.map((option, index) => ({
952
+ text: this.getValueColorName(option.color),
953
+ value: index,
954
+ })),
955
+ });
956
+ conditionValueColorInput.on('change', (ev) => {
957
+ const selectedOption = this.valueColorOptions[ev.value];
958
+ this.setConditionalFormatting(cell, 'valueColor', selectedOption.color);
959
+ });
960
+ // Add conditional hide section
961
+ const hideFolder = pane.addFolder({
962
+ title: 'Conditional Hide Cell',
963
+ expanded: false,
964
+ });
965
+ // Enable/disable conditional hide
966
+ const hideConditionEnabledInput = hideFolder.addBinding(config, 'hideConditionEnabled', {
967
+ label: 'Enable Hide Conditions',
968
+ });
969
+ hideConditionEnabledInput.on('change', (ev) => {
970
+ this.setHideCondition(cell, 'enabled', ev.value);
971
+ });
972
+ // Variable selector for hide condition
973
+ const hideVariableOptions = this.getAllAvailableVariables();
974
+ if (hideVariableOptions.length > 0) {
975
+ // Set default variable to current cell's field if not already set
976
+ if (!config.hideConditionVariable) {
977
+ config.hideConditionVariable = cell.field;
978
+ this.setHideCondition(cell, 'variable', cell.field);
979
+ }
980
+ const hideConditionVariableInput = hideFolder.addBinding(config, 'hideConditionVariable', {
981
+ view: 'list',
982
+ label: 'Variable',
983
+ options: hideVariableOptions,
984
+ });
985
+ hideConditionVariableInput.on('change', (ev) => {
986
+ this.setHideCondition(cell, 'variable', ev.value);
987
+ });
988
+ }
989
+ // Hide condition operator - use operators based on cell type
990
+ const hideOperatorOptions = this.getOperatorOptionsForCell(cell);
991
+ const hideOperatorInput = hideFolder.addBinding(config, 'hideConditionOperator', {
992
+ view: 'list',
993
+ label: 'Operator',
994
+ options: hideOperatorOptions,
995
+ });
996
+ hideOperatorInput.on('change', (ev) => {
997
+ this.setHideCondition(cell, 'operator', ev.value);
998
+ });
999
+ // Hide condition value - text input for comparison value
1000
+ const hideConditionValueInput = hideFolder.addBinding(config, 'hideConditionValue', {
1001
+ label: 'Value',
1002
+ });
1003
+ hideConditionValueInput.on('change', (ev) => {
1004
+ this.setHideCondition(cell, 'value', ev.value);
1005
+ });
1006
+ // Add delete button
1007
+ const deleteBtn = pane.addButton({ title: 'Delete Cell' });
1008
+ deleteBtn.on('click', () => {
1009
+ this.removeCellFromRows(cell.field);
1010
+ this.closeSettingsPopper();
1011
+ });
1012
+ this.settingsPanes.set(cell.field, pane);
1013
+ return pane;
1014
+ }
1015
+ addCellTypeSpecificControls(pane, config, cell) {
1016
+ const cellType = cell.type || 'string';
1017
+ // Create a tab for the current cell type only
1018
+ const tabTitle = this.getCellTypeTabTitle(cellType);
1019
+ if (tabTitle) {
1020
+ const tab = pane.addTab({
1021
+ pages: [{ title: tabTitle }],
1022
+ });
1023
+ const tabPage = tab.pages[0];
1024
+ // Add controls based on cell type
1025
+ switch (cellType) {
1026
+ case 'string':
1027
+ this.addStringControls(tabPage, config, cell);
1028
+ break;
1029
+ case 'link':
1030
+ this.addLinkControls(tabPage, config, cell);
1031
+ break;
1032
+ case 'number':
1033
+ case 'progress':
1034
+ this.addNumberControls(tabPage, config, cell);
1035
+ break;
1036
+ case 'button':
1037
+ this.addButtonControls(tabPage, config, cell);
1038
+ break;
1039
+ case 'currency':
1040
+ this.addCurrencyControls(tabPage, config, cell);
1041
+ break;
1042
+ case 'date':
1043
+ this.addDateProgressControls(tabPage, config, cell);
1044
+ break;
1045
+ }
1046
+ }
1047
+ }
1048
+ getCellTypeTabTitle(cellType) {
1049
+ const typeTitles = {
1050
+ string: 'String Settings',
1051
+ link: 'Link Settings',
1052
+ number: 'Number Settings',
1053
+ button: 'Button Settings',
1054
+ currency: 'Currency Settings',
1055
+ date: 'Date Settings',
1056
+ progress: 'Progress Settings',
1057
+ };
1058
+ return typeTitles[cellType] || 'Cell Settings';
1059
+ }
1060
+ addStringControls(pane, config, cell) {
1061
+ // Value Bold
1062
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1063
+ label: 'Value Bold',
1064
+ });
1065
+ fontInput.on('change', () => {
1066
+ this.setFontWeight(cell);
1067
+ });
1068
+ // Value Variant
1069
+ const valueVariantOptions = [
1070
+ { text: 'Default', value: 'default' },
1071
+ { text: 'Primary', value: 'primary' },
1072
+ { text: 'Success', value: 'success' },
1073
+ { text: 'Warning', value: 'warning' },
1074
+ { text: 'Error', value: 'error' },
1075
+ { text: 'Info', value: 'info' },
1076
+ { text: 'Custom', value: 'custom' },
1077
+ ];
1078
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1079
+ view: 'list',
1080
+ label: 'Value Color',
1081
+ options: valueVariantOptions,
1082
+ });
1083
+ valueVariantInput.on('change', (ev) => {
1084
+ if (ev.value === 'custom') {
1085
+ this.enableValueCustomStyles(cell);
1086
+ }
1087
+ else {
1088
+ this.setValueVariant(ev.value, cell);
1089
+ }
1090
+ });
1091
+ }
1092
+ addLinkControls(pane, config, cell) {
1093
+ // Link Type selector
1094
+ const linkTypeInput = pane.addBinding(config, 'linkType', {
1095
+ view: 'list',
1096
+ label: 'Link Type',
1097
+ options: [
1098
+ { text: 'Custom URL', value: 'custom' },
1099
+ { text: 'Case Variable', value: 'case' },
1100
+ ],
1101
+ });
1102
+ linkTypeInput.on('change', (ev) => {
1103
+ this.setLinkType(cell, ev.value);
1104
+ });
1105
+ // Custom URL input (shown when linkType is 'custom')
1106
+ const hrefInput = pane.addBinding(config, 'href', {
1107
+ label: 'Custom URL',
1108
+ });
1109
+ hrefInput.on('change', (ev) => {
1110
+ this.setHref(cell, ev.value);
1111
+ });
1112
+ // Variable selector (shown when linkType is 'case')
1113
+ const variableOptions = this.getAllAvailableVariables();
1114
+ let linkVariableInput = null;
1115
+ if (variableOptions.length > 0) {
1116
+ linkVariableInput = pane.addBinding(config, 'linkVariable', {
1117
+ view: 'list',
1118
+ label: 'Variable',
1119
+ options: variableOptions,
1120
+ });
1121
+ linkVariableInput.on('change', (ev) => {
1122
+ this.setLinkVariable(cell, ev.value);
1123
+ });
1124
+ }
1125
+ // Show/hide inputs based on linkType
1126
+ const toggleInputVisibility = () => {
1127
+ const isCustom = config.linkType === 'custom';
1128
+ if (hrefInput.element) {
1129
+ hrefInput.element.style.display = isCustom ? '' : 'none';
1130
+ }
1131
+ if (linkVariableInput && linkVariableInput.element) {
1132
+ linkVariableInput.element.style.display = isCustom ? 'none' : '';
1133
+ }
1134
+ };
1135
+ // Initial visibility
1136
+ toggleInputVisibility();
1137
+ // Update visibility when linkType changes
1138
+ linkTypeInput.on('change', () => {
1139
+ setTimeout(toggleInputVisibility, 0);
1140
+ });
1141
+ }
1142
+ addNumberControls(pane, config, cell) {
1143
+ // Value Bold
1144
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1145
+ label: 'Value Bold',
1146
+ });
1147
+ fontInput.on('change', () => {
1148
+ this.setFontWeight(cell);
1149
+ });
1150
+ // Value Variant
1151
+ const valueVariantOptions = [
1152
+ { text: 'Default', value: 'default' },
1153
+ { text: 'Primary', value: 'primary' },
1154
+ { text: 'Success', value: 'success' },
1155
+ { text: 'Warning', value: 'warning' },
1156
+ { text: 'Error', value: 'error' },
1157
+ { text: 'Info', value: 'info' },
1158
+ { text: 'Custom', value: 'custom' },
1159
+ ];
1160
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1161
+ view: 'list',
1162
+ label: 'Value Color',
1163
+ options: valueVariantOptions,
1164
+ });
1165
+ valueVariantInput.on('change', (ev) => {
1166
+ if (ev.value === 'custom') {
1167
+ this.enableValueCustomStyles(cell);
1168
+ }
1169
+ else {
1170
+ this.setValueVariant(ev.value, cell);
1171
+ }
1172
+ });
1173
+ }
1174
+ addButtonControls(pane, config, cell) {
1175
+ // Button Variant
1176
+ const variantInput = pane.addBinding(config, 'buttonVariant', {
1177
+ view: 'list',
1178
+ label: 'Button Variant',
1179
+ options: [
1180
+ { text: 'Contained', value: 'contained' },
1181
+ { text: 'Outlined', value: 'outlined' },
1182
+ { text: 'Text', value: 'text' },
1183
+ { text: 'Dashed', value: 'dashed' },
1184
+ ],
1185
+ });
1186
+ variantInput.on('change', (ev) => {
1187
+ this.setButtonVariant(cell, ev.value);
1188
+ });
1189
+ // Button Color
1190
+ const colorInput = pane.addBinding(config, 'buttonColor', {
1191
+ view: 'list',
1192
+ label: 'Button Color',
1193
+ options: [
1194
+ { text: 'Primary', value: 'primary' },
1195
+ { text: 'Secondary', value: 'secondary' },
1196
+ { text: 'Error', value: 'error' },
1197
+ { text: 'Warning', value: 'warning' },
1198
+ { text: 'AI', value: 'ai' },
1199
+ ],
1200
+ });
1201
+ colorInput.on('change', (ev) => {
1202
+ this.setButtonColor(cell, ev.value);
1203
+ });
1204
+ // Button Full Width
1205
+ const fullWidthInput = pane.addBinding(config, 'buttonFullWidth', {
1206
+ label: 'Button Full Width',
1207
+ });
1208
+ fullWidthInput.on('change', (ev) => {
1209
+ this.setButtonFullWidth(cell, ev.value);
1210
+ });
1211
+ // Add link configuration for buttons (same as links)
1212
+ // Link Type selector
1213
+ const linkTypeInput = pane.addBinding(config, 'linkType', {
1214
+ view: 'list',
1215
+ label: 'Link Type',
1216
+ options: [
1217
+ { text: 'Custom URL', value: 'custom' },
1218
+ { text: 'Case Variable', value: 'case' },
1219
+ ],
1220
+ });
1221
+ linkTypeInput.on('change', (ev) => {
1222
+ this.setLinkType(cell, ev.value);
1223
+ });
1224
+ // Custom URL input (shown when linkType is 'custom')
1225
+ const hrefInput = pane.addBinding(config, 'href', {
1226
+ label: 'Custom URL',
1227
+ });
1228
+ hrefInput.on('change', (ev) => {
1229
+ this.setHref(cell, ev.value);
1230
+ });
1231
+ // Variable selector (shown when linkType is 'case')
1232
+ const variableOptions = this.getAllAvailableVariables();
1233
+ let linkVariableInput = null;
1234
+ if (variableOptions.length > 0) {
1235
+ linkVariableInput = pane.addBinding(config, 'linkVariable', {
1236
+ view: 'list',
1237
+ label: 'Variable',
1238
+ options: variableOptions,
1239
+ });
1240
+ linkVariableInput.on('change', (ev) => {
1241
+ this.setLinkVariable(cell, ev.value);
1242
+ });
1243
+ }
1244
+ // Show/hide inputs based on linkType
1245
+ const toggleInputVisibility = () => {
1246
+ const isCustom = config.linkType === 'custom';
1247
+ if (hrefInput.element) {
1248
+ hrefInput.element.style.display = isCustom ? '' : 'none';
1249
+ }
1250
+ if (linkVariableInput && linkVariableInput.element) {
1251
+ linkVariableInput.element.style.display = isCustom ? 'none' : '';
1252
+ }
1253
+ };
1254
+ // Initial visibility
1255
+ toggleInputVisibility();
1256
+ // Update visibility when linkType changes
1257
+ linkTypeInput.on('change', () => {
1258
+ setTimeout(toggleInputVisibility, 0);
1259
+ });
1260
+ }
1261
+ addCurrencyControls(pane, config, cell) {
1262
+ // Value Bold
1263
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1264
+ label: 'Value Bold',
1265
+ });
1266
+ fontInput.on('change', () => {
1267
+ this.setFontWeight(cell);
1268
+ });
1269
+ // Value Variant
1270
+ const valueVariantOptions = [
1271
+ { text: 'Default', value: 'default' },
1272
+ { text: 'Primary', value: 'primary' },
1273
+ { text: 'Success', value: 'success' },
1274
+ { text: 'Warning', value: 'warning' },
1275
+ { text: 'Error', value: 'error' },
1276
+ { text: 'Info', value: 'info' },
1277
+ { text: 'Custom', value: 'custom' },
1278
+ ];
1279
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1280
+ view: 'list',
1281
+ label: 'Value Color',
1282
+ options: valueVariantOptions,
1283
+ });
1284
+ valueVariantInput.on('change', (ev) => {
1285
+ if (ev.value === 'custom') {
1286
+ this.enableValueCustomStyles(cell);
1287
+ }
1288
+ else {
1289
+ this.setValueVariant(ev.value, cell);
1290
+ }
1291
+ });
1292
+ // Number of Decimals
1293
+ const decimalInput = pane.addBinding(config, 'numberOfDecimal', {
1294
+ label: 'Number of Decimals',
1295
+ min: 0,
1296
+ max: 10,
1297
+ step: 1,
1298
+ });
1299
+ decimalInput.on('change', (ev) => {
1300
+ this.setNumberOfDecimal(cell, ev.value);
1301
+ });
1302
+ // Currency Type
1303
+ const currencyInput = pane.addBinding(config, 'currencyType', {
1304
+ view: 'list',
1305
+ label: 'Currency Type',
1306
+ options: [
1307
+ { text: 'CZK', value: 'CZK' },
1308
+ { text: 'EUR', value: 'EUR' },
1309
+ { text: 'USD', value: 'USD' },
1310
+ { text: 'GBP', value: 'GBP' },
1311
+ { text: 'CHF', value: 'CHF' },
1312
+ { text: 'PLN', value: 'PLN' },
1313
+ { text: 'HUF', value: 'HUF' },
1314
+ { text: 'JPY', value: 'JPY' },
1315
+ { text: 'AUD', value: 'AUD' },
1316
+ { text: 'CAD', value: 'CAD' },
1317
+ { text: 'NOK', value: 'NOK' },
1318
+ { text: 'SEK', value: 'SEK' },
1319
+ { text: 'DKK', value: 'DKK' },
1320
+ { text: 'CNY', value: 'CNY' },
1321
+ { text: 'RUB', value: 'RUB' },
1322
+ ],
1323
+ });
1324
+ currencyInput.on('change', (ev) => {
1325
+ this.setCurrencyType(cell, ev.value);
1326
+ });
1327
+ }
1328
+ addDateProgressControls(pane, config, cell) {
1329
+ // Value Bold
1330
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1331
+ label: 'Value Bold',
1332
+ });
1333
+ fontInput.on('change', () => {
1334
+ this.setFontWeight(cell);
1335
+ });
1336
+ // Value Variant
1337
+ const valueVariantOptions = [
1338
+ { text: 'Default', value: 'default' },
1339
+ { text: 'Primary', value: 'primary' },
1340
+ { text: 'Success', value: 'success' },
1341
+ { text: 'Warning', value: 'warning' },
1342
+ { text: 'Error', value: 'error' },
1343
+ { text: 'Info', value: 'info' },
1344
+ { text: 'Custom', value: 'custom' },
1345
+ ];
1346
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1347
+ view: 'list',
1348
+ label: 'Value Color',
1349
+ options: valueVariantOptions,
1350
+ });
1351
+ valueVariantInput.on('change', (ev) => {
1352
+ if (ev.value === 'custom') {
1353
+ this.enableValueCustomStyles(cell);
1354
+ }
1355
+ else {
1356
+ this.setValueVariant(ev.value, cell);
1357
+ }
1358
+ });
1359
+ // Progress Color (only for progress type)
1360
+ if (cell.type === 'progress') {
1361
+ const progressColorInput = pane.addBinding(config, 'progressColor', {
1362
+ view: 'list',
1363
+ label: 'Progress Color',
1364
+ options: [
1365
+ { text: 'Primary', value: 'primary' },
1366
+ { text: 'Success', value: 'success' },
1367
+ { text: 'Warning', value: 'warning' },
1368
+ { text: 'Error', value: 'error' },
1369
+ { text: 'Info', value: 'info' },
1370
+ ],
1371
+ });
1372
+ progressColorInput.on('change', (ev) => {
1373
+ this.setProgressColor(cell, ev.value);
1374
+ });
1375
+ }
1376
+ }
1377
+ getValueColorName(valueColor) {
1378
+ const colorMap = {
1379
+ 'var(--text-primary)': 'Default',
1380
+ 'var(--color-success-main)': 'Success',
1381
+ 'var(--color-error-main)': 'Error',
1382
+ 'var(--color-warning-main)': 'Warning',
1383
+ 'var(--color-info-main)': 'Info',
1384
+ 'var(--color-primary-main)': 'Primary',
1385
+ };
1386
+ return colorMap[valueColor] || 'Unknown';
1387
+ }
1388
+ getBackgroundColorName(backgroundColor) {
1389
+ const colorMap = {
1390
+ transparent: 'None',
1391
+ 'var(--color-success-light)': 'Success',
1392
+ 'var(--color-error-light)': 'Error',
1393
+ 'var(--color-warning-light)': 'Warning',
1394
+ 'var(--color-info-light)': 'Info',
1395
+ 'var(--color-primary-light)': 'Primary',
1396
+ };
1397
+ return colorMap[backgroundColor] || 'Unknown';
1398
+ }
1399
+ getVariableValue(fieldName) {
1400
+ // First check in current rows
1401
+ const rowCell = this.rows.find((cell) => cell.field === fieldName);
1402
+ if (rowCell) {
1403
+ return rowCell.value;
1404
+ }
1405
+ // Then check in data object
1406
+ const dataItem = this.data?.[fieldName];
1407
+ if (dataItem) {
1408
+ return dataItem.ivar_value;
1409
+ }
1410
+ return '';
1411
+ }
1412
+ evaluateCondition(variableField, conditionValue, operator) {
1413
+ // Get the value of the selected variable
1414
+ const variableValue = this.getVariableValue(variableField);
1415
+ // For isEmpty/isNotEmpty operators, check the raw value first
1416
+ if (operator === 'isEmpty') {
1417
+ return (variableValue === null ||
1418
+ variableValue === undefined ||
1419
+ variableValue === '' ||
1420
+ (typeof variableValue === 'string' && variableValue.trim() === ''));
1421
+ }
1422
+ if (operator === 'isNotEmpty') {
1423
+ return !(variableValue === null ||
1424
+ variableValue === undefined ||
1425
+ variableValue === '' ||
1426
+ (typeof variableValue === 'string' && variableValue.trim() === ''));
1427
+ }
1428
+ const variableStr = String(variableValue || '').toLowerCase();
1429
+ const conditionStr = String(conditionValue || '').toLowerCase();
1430
+ const variableNum = parseFloat(variableValue);
1431
+ const conditionNum = parseFloat(conditionValue);
1432
+ switch (operator) {
1433
+ case '=':
1434
+ return variableStr === conditionStr;
1435
+ case '!=':
1436
+ return variableStr !== conditionStr;
1437
+ case '>':
1438
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum > conditionNum;
1439
+ case '>=':
1440
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum >= conditionNum;
1441
+ case '<':
1442
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum < conditionNum;
1443
+ case '<=':
1444
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum <= conditionNum;
1445
+ case 'contains':
1446
+ return variableStr.includes(conditionStr);
1447
+ case 'doesNotContain':
1448
+ return !variableStr.includes(conditionStr);
1449
+ case 'startsWith':
1450
+ return variableStr.startsWith(conditionStr);
1451
+ case 'endsWith':
1452
+ return variableStr.endsWith(conditionStr);
1453
+ // Legacy support for old operator names
1454
+ case 'equals':
1455
+ return variableStr === conditionStr;
1456
+ case 'notEquals':
1457
+ return variableStr !== conditionStr;
1458
+ case 'greater':
1459
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum > conditionNum;
1460
+ case 'less':
1461
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum < conditionNum;
1462
+ default:
1463
+ return false;
1464
+ }
1465
+ }
1466
+ computeCellStyles(cell) {
1467
+ // Priority order:
1468
+ // 1. Conditional formatting (highest)
1469
+ // 2. Custom cellStyle (if cellCustomStyles = true)
1470
+ // 3. Semantic cellVariant
1471
+ // 4. Default styles (lowest)
1472
+ let styles = {};
1473
+ // 4. Default styles (base)
1474
+ // (none for now, could add default cell styling here)
1475
+ // 3. Semantic cellVariant
1476
+ if (cell.cellVariant && cell.cellVariant !== 'default') {
1477
+ const variantStyle = this.getCellVariantStyle(cell.cellVariant);
1478
+ styles = { ...styles, ...variantStyle };
1479
+ }
1480
+ // 2. Custom cellStyle (if explicitly enabled)
1481
+ if (cell.cellCustomStyles && cell.cellStyle) {
1482
+ styles = { ...styles, ...cell.cellStyle };
1483
+ }
1484
+ // 1. Conditional formatting (highest priority)
1485
+ const conditionalFormatting = cell.conditionalFormatting;
1486
+ if (conditionalFormatting?.enabled && conditionalFormatting?.variable) {
1487
+ const conditionMet = this.evaluateCondition(conditionalFormatting.variable, conditionalFormatting.value, conditionalFormatting.operator);
1488
+ if (conditionMet) {
1489
+ styles = {
1490
+ ...styles,
1491
+ backgroundColor: conditionalFormatting.backgroundColor,
1492
+ borderRadius: '8px',
1493
+ border: this.backgroundColorOptions.find((opt) => opt.backgroundColor === conditionalFormatting.backgroundColor)?.border || '1px solid transparent',
1494
+ };
1495
+ }
1496
+ }
1497
+ return styles;
1498
+ }
1499
+ getCellVariantStyle(variant) {
1500
+ const variantMap = {
1501
+ primary: {
1502
+ backgroundColor: 'var(--color-primary-light)',
1503
+ borderRadius: '8px',
1504
+ border: '1px solid var(--color-primary-dark)',
1505
+ },
1506
+ success: {
1507
+ backgroundColor: 'var(--color-success-light)',
1508
+ borderRadius: '8px',
1509
+ border: '1px solid var(--color-success-dark)',
1510
+ },
1511
+ warning: {
1512
+ backgroundColor: 'var(--color-warning-light)',
1513
+ borderRadius: '8px',
1514
+ border: '1px solid var(--color-warning-dark)',
1515
+ },
1516
+ error: {
1517
+ backgroundColor: 'var(--color-error-light)',
1518
+ borderRadius: '8px',
1519
+ border: '1px solid var(--color-error-dark)',
1520
+ },
1521
+ info: {
1522
+ backgroundColor: 'var(--color-info-light)',
1523
+ borderRadius: '8px',
1524
+ border: '1px solid var(--color-info-dark)',
1525
+ },
1526
+ };
1527
+ return variantMap[variant] || {};
1528
+ }
1529
+ computeValueStyles(cell) {
1530
+ // Priority order:
1531
+ // 1. Conditional formatting value color (highest)
1532
+ // 2. Custom valueStyle (if valueCustomStyles = true)
1533
+ // 3. Semantic valueVariant + Independent fontWeight
1534
+ // 4. Default styles (lowest)
1535
+ let styles = {};
1536
+ // 4. Default styles (base)
1537
+ // (none for now, could add default value styling here)
1538
+ // 3. Semantic valueVariant
1539
+ if (cell.valueVariant && cell.valueVariant !== 'default') {
1540
+ const variantStyle = this.getValueVariantStyle(cell.valueVariant);
1541
+ styles = { ...styles, ...variantStyle };
1542
+ }
1543
+ // 3b. Independent fontWeight (works alongside variants)
1544
+ if (cell.fontWeight && cell.fontWeight !== 'normal') {
1545
+ styles = { ...styles, fontWeight: cell.fontWeight };
1546
+ }
1547
+ // 2. Custom valueStyle (if explicitly enabled)
1548
+ if (cell.valueCustomStyles && cell.valueStyle) {
1549
+ styles = { ...styles, ...cell.valueStyle };
1550
+ }
1551
+ // 1. Conditional formatting value color (highest priority)
1552
+ const conditionalFormatting = cell.conditionalFormatting;
1553
+ if (conditionalFormatting?.enabled && conditionalFormatting?.variable) {
1554
+ const conditionMet = this.evaluateCondition(conditionalFormatting.variable, conditionalFormatting.value, conditionalFormatting.operator);
1555
+ if (conditionMet && conditionalFormatting.valueColor) {
1556
+ styles = {
1557
+ ...styles,
1558
+ color: conditionalFormatting.valueColor,
1559
+ };
1560
+ }
1561
+ }
1562
+ return styles;
1563
+ }
1564
+ getValueVariantStyle(variant) {
1565
+ const variantMap = {
1566
+ primary: {
1567
+ color: 'var(--color-primary-main)',
1568
+ fontWeight: '500',
1569
+ },
1570
+ success: {
1571
+ color: 'var(--color-success-main)',
1572
+ fontWeight: '500',
1573
+ },
1574
+ warning: {
1575
+ color: 'var(--color-warning-main)',
1576
+ fontWeight: '500',
1577
+ },
1578
+ error: {
1579
+ color: 'var(--color-error-main)',
1580
+ fontWeight: '500',
1581
+ },
1582
+ info: {
1583
+ color: 'var(--color-info-main)',
1584
+ fontWeight: '500',
1585
+ },
1586
+ };
1587
+ return variantMap[variant] || {};
1588
+ }
1589
+ shouldHideCell(cell) {
1590
+ const hideCondition = cell.hideCondition;
1591
+ if (!hideCondition?.enabled || !hideCondition?.variable) {
1592
+ return false;
1593
+ }
1594
+ return this.evaluateCondition(hideCondition.variable, hideCondition.value, hideCondition.operator);
1595
+ }
386
1596
  initSortable() {
387
1597
  this.updateComplete.then(() => {
388
1598
  const containers = this.shadowRoot?.querySelectorAll('.grid-container');
@@ -424,17 +1634,92 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
424
1634
  setLocale(lang);
425
1635
  }
426
1636
  }
427
- isActiveBackground(cell, color) {
428
- const bg = cell?.cellStyle?.backgroundColor;
429
- if (!bg && color === 'transparent')
430
- return true; // If nothing is set → consider transparent as active
431
- return bg === color;
432
- }
433
- setCellSize(size, cell) {
1637
+ setCellSize(size, cell, breakpoint = 'lg') {
434
1638
  if (!cell.size) {
435
1639
  cell.size = {};
436
1640
  }
437
- cell.size.lg = size;
1641
+ cell.size[breakpoint] = size;
1642
+ this.rows = [...this.rows];
1643
+ this.handleSettingsChanged(this.rows);
1644
+ }
1645
+ setCellType(cell, type) {
1646
+ cell.type = type;
1647
+ this.rows = [...this.rows];
1648
+ this.handleSettingsChanged(this.rows);
1649
+ // Simply close the settings popper when cell type changes
1650
+ // User can reopen to see the new type-specific controls
1651
+ this.closeSettingsPopper();
1652
+ }
1653
+ setHideCondition(cell, property, value) {
1654
+ // Initialize hide condition if not exists
1655
+ if (!cell.hideCondition) {
1656
+ cell.hideCondition = {};
1657
+ }
1658
+ // Set the property
1659
+ cell.hideCondition[property] = value;
1660
+ this.rows = [...this.rows];
1661
+ this.handleSettingsChanged(this.rows);
1662
+ }
1663
+ setHref(cell, href) {
1664
+ cell.href = href;
1665
+ this.rows = [...this.rows];
1666
+ this.handleSettingsChanged(this.rows);
1667
+ }
1668
+ setLinkType(cell, linkType) {
1669
+ cell.linkType = linkType;
1670
+ // Clear other link properties when switching types
1671
+ if (linkType === 'custom') {
1672
+ cell.linkVariable = '';
1673
+ cell.dynamicLink = '';
1674
+ }
1675
+ else {
1676
+ cell.href = '';
1677
+ }
1678
+ this.rows = [...this.rows];
1679
+ this.handleSettingsChanged(this.rows);
1680
+ }
1681
+ setLinkVariable(cell, linkVariable) {
1682
+ cell.linkVariable = linkVariable;
1683
+ this.rows = [...this.rows];
1684
+ this.handleSettingsChanged(this.rows);
1685
+ }
1686
+ setNumberOfDecimal(cell, numberOfDecimal) {
1687
+ cell.numberOfDecimal = numberOfDecimal;
1688
+ this.rows = [...this.rows];
1689
+ this.handleSettingsChanged(this.rows);
1690
+ }
1691
+ setButtonVariant(cell, variant) {
1692
+ cell.buttonVariant = variant;
1693
+ this.rows = [...this.rows];
1694
+ this.handleSettingsChanged(this.rows);
1695
+ }
1696
+ setButtonColor(cell, color) {
1697
+ cell.buttonColor = color;
1698
+ this.rows = [...this.rows];
1699
+ this.handleSettingsChanged(this.rows);
1700
+ }
1701
+ setButtonFullWidth(cell, fullWidth) {
1702
+ cell.buttonFullWidth = fullWidth;
1703
+ this.rows = [...this.rows];
1704
+ this.handleSettingsChanged(this.rows);
1705
+ }
1706
+ setCurrencyType(cell, currencyType) {
1707
+ cell.currencyType = currencyType;
1708
+ this.rows = [...this.rows];
1709
+ this.handleSettingsChanged(this.rows);
1710
+ }
1711
+ setProgressColor(cell, progressColor) {
1712
+ cell.progressColor = progressColor;
1713
+ this.rows = [...this.rows];
1714
+ this.handleSettingsChanged(this.rows);
1715
+ }
1716
+ setCellHeaderName(cell, headerName) {
1717
+ cell.headerName = headerName;
1718
+ this.rows = [...this.rows];
1719
+ this.handleSettingsChanged(this.rows);
1720
+ }
1721
+ setCellValue(cell, value) {
1722
+ cell.value = value;
438
1723
  this.rows = [...this.rows];
439
1724
  this.handleSettingsChanged(this.rows);
440
1725
  }
@@ -494,6 +1779,31 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
494
1779
  this.handleSettingsChanged(newRows);
495
1780
  }
496
1781
  }
1782
+ replaceDynamicVariables(template) {
1783
+ // Replace ${variableName} patterns with actual variable values
1784
+ return template.replace(/\$\{([^}]+)\}/g, (match, variableName) => {
1785
+ const variableValue = this.getVariableValue(variableName.trim());
1786
+ return String(variableValue || '');
1787
+ });
1788
+ }
1789
+ getLinkUrl(cell) {
1790
+ if (cell.linkType === 'case') {
1791
+ if (cell.dynamicLink) {
1792
+ // Use dynamic link template and replace variables
1793
+ return this.replaceDynamicVariables(cell.dynamicLink);
1794
+ }
1795
+ else if (cell.linkVariable) {
1796
+ // Get value from the selected variable (backward compatibility)
1797
+ const variableValue = this.getVariableValue(cell.linkVariable);
1798
+ return String(variableValue || '');
1799
+ }
1800
+ return '';
1801
+ }
1802
+ else {
1803
+ // Use custom href
1804
+ return cell.href || '';
1805
+ }
1806
+ }
497
1807
  render() {
498
1808
  if (this.hideTabWhen)
499
1809
  return null;
@@ -528,11 +1838,11 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
528
1838
  .reverse()
529
1839
  .map((bp) => cell.size?.[bp])
530
1840
  .find((s) => s !== undefined) ?? 2);
531
- const classes = `cell--span${spanSize} cell`;
1841
+ const classes = `cell--span${spanSize} cell ${this.shouldHideCell(cell) ? 'hidden-cell' : ''}`;
532
1842
  return html `
533
1843
  <div
534
1844
  class="${classes}"
535
- style="${styleMap(cell.cellStyle || {})}"
1845
+ style="${styleMap(this.computeCellStyles(cell))}"
536
1846
  data-field="${cell.field}"
537
1847
  >
538
1848
  ${cell?.type === 'button'
@@ -555,8 +1865,20 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
555
1865
  `}
556
1866
  ${this.enableSettings
557
1867
  ? html `
558
- <div style="text-align: right; margin-top: 1rem;">
1868
+ <div
1869
+ style="display: flex; gap: 0.5rem; justify-content: right; margin-top: 1rem; flex-wrap: wrap;"
1870
+ >
1871
+ <lit-button
1872
+ color="secondary"
1873
+ variant="${'dashed'}"
1874
+ label="${msg('Přiřadit vlastní buňku')}"
1875
+ icon="add"
1876
+ .fullWidth=${this.isMobile}
1877
+ @click="${this.addCustomEmptyCell}"
1878
+ class="add-variable-button"
1879
+ ></lit-button>
559
1880
  <lit-button
1881
+ color="secondary"
560
1882
  variant="${'dashed'}"
561
1883
  label="${msg('Přiřadit proměnnou')}"
562
1884
  icon="add"
@@ -598,6 +1920,13 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
598
1920
  name.toLowerCase().includes(this.filterText));
599
1921
  })
600
1922
  .sort((a, b) => {
1923
+ // Checked items go to top
1924
+ const aChecked = this.existingFields.includes(a);
1925
+ const bChecked = this.existingFields.includes(b);
1926
+ if (aChecked && !bChecked)
1927
+ return -1;
1928
+ if (!aChecked && bChecked)
1929
+ return 1;
601
1930
  const aIsUnderscore = a.startsWith('_');
602
1931
  const bIsUnderscore = b.startsWith('_');
603
1932
  if (aIsUnderscore && !bIsUnderscore)
@@ -617,6 +1946,7 @@ let LitCaseVariablesTab = class LitCaseVariablesTab extends LitElement {
617
1946
  .checked=${this.existingFields.includes(key)}
618
1947
  ></lit-checkbox>
619
1948
  ${this.data?.[key]?.[`tvar_name_${this.userLang}`] || key}
1949
+ (${key})
620
1950
  </span>
621
1951
  </lit-menu-item>
622
1952
  `)}
@@ -743,6 +2073,7 @@ LitCaseVariablesTab.styles = [
743
2073
  .header-buttons {
744
2074
  display: flex;
745
2075
  gap: 0.5rem;
2076
+ color: var(--text-secondary, #777);
746
2077
  }
747
2078
 
748
2079
  .size-button {
@@ -843,6 +2174,20 @@ LitCaseVariablesTab.styles = [
843
2174
  grid-template-columns: repeat(auto-fill, minmax(0, 1fr));
844
2175
  }
845
2176
  }
2177
+
2178
+ .hidden-cell {
2179
+ display: none;
2180
+ }
2181
+
2182
+ .tweakpane-container {
2183
+ min-width: 250px;
2184
+ max-width: 300px;
2185
+ }
2186
+
2187
+ /* Basic Tweakpane in tooltip styling - applying to document to bypass shadow DOM */
2188
+ :host([data-tweakpane-loaded]) {
2189
+ display: block;
2190
+ }
846
2191
  `,
847
2192
  ];
848
2193
  __decorate([
@@ -887,6 +2232,12 @@ __decorate([
887
2232
  __decorate([
888
2233
  state()
889
2234
  ], LitCaseVariablesTab.prototype, "isMobile", void 0);
2235
+ __decorate([
2236
+ state()
2237
+ ], LitCaseVariablesTab.prototype, "activeSettingsCell", void 0);
2238
+ __decorate([
2239
+ state()
2240
+ ], LitCaseVariablesTab.prototype, "settingsPopperOpen", void 0);
890
2241
  LitCaseVariablesTab = __decorate([
891
2242
  customElement('lit-case-variables-tab')
892
2243
  ], LitCaseVariablesTab);