@valtimo/process-management 13.52.0 → 13.54.0

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.
@@ -1500,7 +1500,12 @@ class ExpressionAutocomplete {
1500
1500
  this.stylesInjected = false;
1501
1501
  this.observer = null;
1502
1502
  this.documentClickHandlers = [];
1503
+ this.selectedElementId = null;
1504
+ this.manualModeKeys = new Set();
1503
1505
  this.injectStyles();
1506
+ eventBus.on('selection.changed', (event) => {
1507
+ this.selectedElementId = event?.newSelection?.[0]?.id ?? null;
1508
+ });
1504
1509
  eventBus.on('diagram.destroy', () => {
1505
1510
  this.dispose();
1506
1511
  });
@@ -1512,6 +1517,7 @@ class ExpressionAutocomplete {
1512
1517
  this.observer = null;
1513
1518
  }
1514
1519
  this.panelContainer = null;
1520
+ this.manualModeKeys.clear();
1515
1521
  }
1516
1522
  cleanupClickHandlers() {
1517
1523
  for (const handler of this.documentClickHandlers) {
@@ -1553,7 +1559,8 @@ class ExpressionAutocomplete {
1553
1559
  }
1554
1560
  isExpressionField(input) {
1555
1561
  const type = input.type?.toLowerCase();
1556
- if (input.tagName !== 'TEXTAREA' && !(input.tagName === 'INPUT' && (!type || type === 'text'))) {
1562
+ if (input.tagName !== 'TEXTAREA' &&
1563
+ !(input.tagName === 'INPUT' && (!type || type === 'text'))) {
1557
1564
  return false;
1558
1565
  }
1559
1566
  if (input.closest('.expression-editor-simple')) {
@@ -1597,7 +1604,7 @@ class ExpressionAutocomplete {
1597
1604
  wrapper.className = 'expression-editor-wrapper';
1598
1605
  const parsed = this.parseExpression(input.value);
1599
1606
  const canUseDropdown = !input.value || (parsed.beanName !== null && parsed.methodName !== null);
1600
- const initialMode = canUseDropdown ? 'simple' : 'technical';
1607
+ const initialMode = canUseDropdown && !this.manualModeKeys.has(this.getModeKey(input)) ? 'simple' : 'technical';
1601
1608
  wrapper.dataset.mode = initialMode;
1602
1609
  input.parentNode?.insertBefore(wrapper, input);
1603
1610
  const toggle = document.createElement('div');
@@ -1628,6 +1635,13 @@ class ExpressionAutocomplete {
1628
1635
  }
1629
1636
  setEditorMode(wrapper, input, mode) {
1630
1637
  wrapper.dataset.mode = mode;
1638
+ const modeKey = this.getModeKey(input);
1639
+ if (mode === 'technical') {
1640
+ this.manualModeKeys.add(modeKey);
1641
+ }
1642
+ else {
1643
+ this.manualModeKeys.delete(modeKey);
1644
+ }
1631
1645
  wrapper.querySelectorAll('.expression-editor-toggle__btn').forEach(btn => {
1632
1646
  btn.classList.toggle('active', btn.dataset.mode === mode);
1633
1647
  });
@@ -1660,6 +1674,11 @@ class ExpressionAutocomplete {
1660
1674
  setTimeout(() => input.blur(), 0);
1661
1675
  }
1662
1676
  }
1677
+ // Panel re-renders on save; key survives new input elements
1678
+ getModeKey(input) {
1679
+ const entryId = input.closest('.bio-properties-panel-entry')?.getAttribute('data-entry-id') || '';
1680
+ return `${this.selectedElementId}|${entryId}|${input.name || input.id}`;
1681
+ }
1663
1682
  renderSimpleMode(container, input) {
1664
1683
  this.cleanupClickHandlers();
1665
1684
  const parsed = this.parseExpression(input.value);
@@ -1845,14 +1864,37 @@ class ExpressionAutocomplete {
1845
1864
  }
1846
1865
  parseExpression(expr) {
1847
1866
  const match = expr.match(/^\$\{([a-zA-Z_]\w*)\.([a-zA-Z_]\w*)\((.*)\)\}$/);
1848
- if (!match)
1867
+ if (!match || !this.isSingleCallArguments(match[3])) {
1849
1868
  return { beanName: null, methodName: null, parameters: [] };
1869
+ }
1850
1870
  return {
1851
1871
  beanName: match[1],
1852
1872
  methodName: match[2],
1853
1873
  parameters: this.parseParameters(match[3]),
1854
1874
  };
1855
1875
  }
1876
+ // Chained calls like `a.b(x).c()` close the first call early
1877
+ isSingleCallArguments(paramsStr) {
1878
+ let depth = 0;
1879
+ let inString = false;
1880
+ let stringChar = '';
1881
+ for (const char of paramsStr) {
1882
+ if (!inString && (char === '"' || char === "'")) {
1883
+ inString = true;
1884
+ stringChar = char;
1885
+ }
1886
+ else if (inString && char === stringChar) {
1887
+ inString = false;
1888
+ }
1889
+ else if (!inString && char === '(') {
1890
+ depth++;
1891
+ }
1892
+ else if (!inString && char === ')' && --depth < 0) {
1893
+ return false;
1894
+ }
1895
+ }
1896
+ return depth === 0;
1897
+ }
1856
1898
  parseParameters(paramsStr) {
1857
1899
  const params = [];
1858
1900
  let current = '';
@@ -1903,9 +1945,7 @@ class ExpressionAutocomplete {
1903
1945
  .replace(/>/g, '&gt;');
1904
1946
  }
1905
1947
  camelCaseToReadable(text) {
1906
- return text
1907
- .replace(/([a-z])([A-Z])/g, '$1 $2')
1908
- .replace(/^./, str => str.toUpperCase());
1948
+ return text.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/^./, str => str.toUpperCase());
1909
1949
  }
1910
1950
  injectStyles() {
1911
1951
  if (this.stylesInjected)