bpmn-js 18.22.1 → 18.24.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.
Files changed (36) hide show
  1. package/dist/assets/diagram-js.css +121 -5
  2. package/dist/bpmn-modeler.development.js +1371 -346
  3. package/dist/bpmn-modeler.production.min.js +98 -58
  4. package/dist/bpmn-navigated-viewer.development.js +2 -2
  5. package/dist/bpmn-navigated-viewer.production.min.js +1 -1
  6. package/dist/bpmn-viewer.development.js +2 -2
  7. package/dist/bpmn-viewer.production.min.js +1 -1
  8. package/lib/features/modeling/Modeling.d.ts +13 -0
  9. package/lib/features/modeling/Modeling.d.ts.map +1 -1
  10. package/lib/features/modeling/Modeling.js +21 -0
  11. package/lib/features/modeling/behavior/CategoryRootElementReferenceBehavior.d.ts +19 -0
  12. package/lib/features/modeling/behavior/CategoryRootElementReferenceBehavior.d.ts.map +1 -0
  13. package/lib/features/modeling/behavior/CategoryRootElementReferenceBehavior.js +157 -0
  14. package/lib/features/modeling/behavior/GroupBehavior.d.ts +2 -8
  15. package/lib/features/modeling/behavior/GroupBehavior.d.ts.map +1 -1
  16. package/lib/features/modeling/behavior/GroupBehavior.js +65 -134
  17. package/lib/features/modeling/behavior/UpdateCategoryValueRefsBehavior.d.ts +17 -0
  18. package/lib/features/modeling/behavior/UpdateCategoryValueRefsBehavior.d.ts.map +1 -0
  19. package/lib/features/modeling/behavior/UpdateCategoryValueRefsBehavior.js +169 -0
  20. package/lib/features/modeling/behavior/UpdateFlowNodeRefsBehavior.d.ts +1 -1
  21. package/lib/features/modeling/behavior/UpdateFlowNodeRefsBehavior.d.ts.map +1 -1
  22. package/lib/features/modeling/behavior/UpdateFlowNodeRefsBehavior.js +35 -37
  23. package/lib/features/modeling/behavior/index.d.ts +4 -0
  24. package/lib/features/modeling/behavior/index.d.ts.map +1 -1
  25. package/lib/features/modeling/behavior/index.js +6 -0
  26. package/lib/features/modeling/behavior/util/CategoryUtil.d.ts +12 -3
  27. package/lib/features/modeling/behavior/util/CategoryUtil.d.ts.map +1 -1
  28. package/lib/features/modeling/behavior/util/CategoryUtil.js +25 -2
  29. package/lib/features/modeling/cmd/UpdateCategoryValueRefsHandler.d.ts +40 -0
  30. package/lib/features/modeling/cmd/UpdateCategoryValueRefsHandler.d.ts.map +1 -0
  31. package/lib/features/modeling/cmd/UpdateCategoryValueRefsHandler.js +424 -0
  32. package/lib/features/modeling/cmd/UpdateFlowNodeRefsHandler.d.ts +0 -8
  33. package/lib/features/modeling/cmd/UpdateFlowNodeRefsHandler.d.ts.map +1 -1
  34. package/lib/features/modeling/cmd/UpdateFlowNodeRefsHandler.js +1 -9
  35. package/lib/features/rules/BpmnRules.js +38 -0
  36. package/package.json +3 -3
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * bpmn-js - bpmn-modeler v18.22.1
2
+ * bpmn-js - bpmn-modeler v18.24.0
3
3
  *
4
4
  * Copyright (c) 2014-present, camunda Services GmbH
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Source Code: https://github.com/bpmn-io/bpmn-js
10
10
  *
11
- * Date: 2026-07-29
11
+ * Date: 2026-08-11
12
12
  */
13
13
  (function (global, factory) {
14
14
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -22571,7 +22571,7 @@
22571
22571
  // document wide unique overlay ids
22572
22572
  var ids$2 = new IdGenerator('ov');
22573
22573
 
22574
- var LOW_PRIORITY$q = 500;
22574
+ var LOW_PRIORITY$s = 500;
22575
22575
 
22576
22576
  /**
22577
22577
  * @typedef {import('../../core/Canvas.js').default} Canvas
@@ -23201,7 +23201,7 @@
23201
23201
 
23202
23202
  // move integration
23203
23203
 
23204
- eventBus.on('element.changed', LOW_PRIORITY$q, function(e) {
23204
+ eventBus.on('element.changed', LOW_PRIORITY$s, function(e) {
23205
23205
  var element = e.element;
23206
23206
 
23207
23207
  var container = self._getOverlayContainer(element, true);
@@ -24283,7 +24283,7 @@
24283
24283
  * @typedef {import('../../model/Types').Shape} Shape
24284
24284
  */
24285
24285
 
24286
- var LOW_PRIORITY$p = 250;
24286
+ var LOW_PRIORITY$r = 250;
24287
24287
  var ARROW_DOWN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.81801948,3.50735931 L10.4996894,9.1896894 L10.5,4 L12,4 L12,12 L4,12 L4,10.5 L9.6896894,10.4996894 L3.75735931,4.56801948 C3.46446609,4.27512627 3.46446609,3.80025253 3.75735931,3.50735931 C4.05025253,3.21446609 4.52512627,3.21446609 4.81801948,3.50735931 Z"/></svg>';
24288
24288
 
24289
24289
  var EMPTY_MARKER = 'bjs-drilldown-empty';
@@ -24308,7 +24308,7 @@
24308
24308
 
24309
24309
  var self = this;
24310
24310
 
24311
- this.executed('shape.toggleCollapse', LOW_PRIORITY$p, function(context) {
24311
+ this.executed('shape.toggleCollapse', LOW_PRIORITY$r, function(context) {
24312
24312
  var shape = context.shape;
24313
24313
 
24314
24314
  // Add overlay to the collapsed shape
@@ -24320,7 +24320,7 @@
24320
24320
  }, true);
24321
24321
 
24322
24322
 
24323
- this.reverted('shape.toggleCollapse', LOW_PRIORITY$p, function(context) {
24323
+ this.reverted('shape.toggleCollapse', LOW_PRIORITY$r, function(context) {
24324
24324
  var shape = context.shape;
24325
24325
 
24326
24326
  // Add overlay to the collapsed shape
@@ -24332,7 +24332,7 @@
24332
24332
  }, true);
24333
24333
 
24334
24334
 
24335
- this.executed([ 'shape.create', 'shape.move', 'shape.delete' ], LOW_PRIORITY$p,
24335
+ this.executed([ 'shape.create', 'shape.move', 'shape.delete' ], LOW_PRIORITY$r,
24336
24336
  function(context) {
24337
24337
  var oldParent = context.oldParent,
24338
24338
  newParent = context.newParent || context.parent,
@@ -24349,7 +24349,7 @@
24349
24349
  }, true);
24350
24350
 
24351
24351
 
24352
- this.reverted([ 'shape.create', 'shape.move', 'shape.delete' ], LOW_PRIORITY$p,
24352
+ this.reverted([ 'shape.create', 'shape.move', 'shape.delete' ], LOW_PRIORITY$r,
24353
24353
  function(context) {
24354
24354
  var oldParent = context.oldParent,
24355
24355
  newParent = context.newParent || context.parent,
@@ -24626,7 +24626,7 @@
24626
24626
  return isPrimaryButton(event) || isAuxiliaryButton(event);
24627
24627
  }
24628
24628
 
24629
- var LOW_PRIORITY$o = 500;
24629
+ var LOW_PRIORITY$q = 500;
24630
24630
 
24631
24631
 
24632
24632
  /**
@@ -24823,7 +24823,7 @@
24823
24823
  eventBus.on([
24824
24824
  'shape.changed',
24825
24825
  'connection.changed'
24826
- ], LOW_PRIORITY$o, function(event) {
24826
+ ], LOW_PRIORITY$q, function(event) {
24827
24827
 
24828
24828
  var element = event.element,
24829
24829
  gfx = event.gfx;
@@ -24831,7 +24831,7 @@
24831
24831
  eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
24832
24832
  });
24833
24833
 
24834
- eventBus.on('interactionEvents.createHit', LOW_PRIORITY$o, function(event) {
24834
+ eventBus.on('interactionEvents.createHit', LOW_PRIORITY$q, function(event) {
24835
24835
  var element = event.element,
24836
24836
  gfx = event.gfx;
24837
24837
 
@@ -25794,7 +25794,7 @@
25794
25794
  Keyboard.prototype.isShift = isShift;
25795
25795
  Keyboard.prototype.isKey = isKey;
25796
25796
 
25797
- var LOW_PRIORITY$n = 500;
25797
+ var LOW_PRIORITY$p = 500;
25798
25798
 
25799
25799
 
25800
25800
  /**
@@ -25810,7 +25810,7 @@
25810
25810
 
25811
25811
  var self = this;
25812
25812
 
25813
- eventBus.on('editorActions.init', LOW_PRIORITY$n, function(event) {
25813
+ eventBus.on('editorActions.init', LOW_PRIORITY$p, function(event) {
25814
25814
 
25815
25815
  var editorActions = event.editorActions;
25816
25816
 
@@ -27977,7 +27977,17 @@
27977
27977
  ${ entry.label }
27978
27978
  </span>
27979
27979
  ` : null }
27980
-
27980
+ </span>
27981
+ ${ entry.description && m$1`
27982
+ <span
27983
+ class="djs-popup-entry-description"
27984
+ >
27985
+ ${ entry.description }
27986
+ </span>
27987
+ ` }
27988
+ </div>
27989
+ ${ (entry.documentationRef || entry.entries) && m$1`
27990
+ <div class="djs-popup-entry-actions">
27981
27991
  ${ entry.documentationRef && m$1`
27982
27992
  <a
27983
27993
  class="djs-popup-entry-docs"
@@ -27990,24 +28000,17 @@
27990
28000
  rel="noopener"
27991
28001
  >
27992
28002
  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
27993
- <path fill-rule="evenodd" clip-rule="evenodd" d="M10.6368 10.6375V5.91761H11.9995V10.6382C11.9995 10.9973 11.8623 11.3141 11.5878 11.5885C11.3134 11.863 10.9966 12.0002 10.6375 12.0002H1.36266C0.982345 12.0002 0.660159 11.8681 0.396102 11.6041C0.132044 11.34 1.52588e-05 11.0178 1.52588e-05 10.6375V1.36267C1.52588e-05 0.98236 0.132044 0.660173 0.396102 0.396116C0.660159 0.132058 0.982345 2.95639e-05 1.36266 2.95639e-05H5.91624V1.36267H1.36266V10.6375H10.6368ZM12 0H7.2794L7.27873 1.36197H9.68701L3.06507 7.98391L4.01541 8.93425L10.6373 2.31231V4.72059H12V0Z" fill="#818798"/>
28003
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M10.6368 10.6375V5.91761H11.9995V10.6382C11.9995 10.9973 11.8623 11.3141 11.5878 11.5885C11.3134 11.863 10.9966 12.0002 10.6375 12.0002H1.36266C0.982345 12.0002 0.660159 11.8681 0.396102 11.6041C0.132044 11.34 1.52588e-05 11.0178 1.52588e-05 10.6375V1.36267C1.52588e-05 0.98236 0.132044 0.660173 0.396102 0.396116C0.660159 0.132058 0.982345 2.95639e-05 1.36266 2.95639e-05H5.91624V1.36267H1.36266V10.6375H10.6368ZM12 0H7.2794L7.27873 1.36197H9.68701L3.06507 7.98391L4.01541 8.93425L10.6373 2.31231V4.72059H12V0Z" fill="currentColor"/>
27994
28004
  </svg>
27995
28005
  </a>
27996
28006
  ` }
27997
- </span>
27998
- ${ entry.description && m$1`
27999
- <span
28000
- class="djs-popup-entry-description"
28001
- >
28002
- ${ entry.description }
28003
- </span>
28004
- ` }
28005
- </div>
28006
- ${ entry.entries && m$1`
28007
- <div class="djs-popup-entry-chevron" aria-hidden="true">
28008
- <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
28009
- <path fill-rule="evenodd" clip-rule="evenodd" d="M3.96967 1.46967C4.26256 1.17678 4.73744 1.17678 5.03033 1.46967L9.03033 5.46967C9.32322 5.76256 9.32322 6.23744 9.03033 6.53033L5.03033 10.5303C4.73744 10.8232 4.26256 10.8232 3.96967 10.5303C3.67678 10.2374 3.67678 9.76256 3.96967 9.46967L7.43934 6L3.96967 2.53033C3.67678 2.23744 3.67678 1.76256 3.96967 1.46967Z" fill="currentColor"/>
28010
- </svg>
28007
+ ${ entry.entries && m$1`
28008
+ <div class="djs-popup-entry-chevron" aria-hidden="true">
28009
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
28010
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M3.96967 1.46967C4.26256 1.17678 4.73744 1.17678 5.03033 1.46967L9.03033 5.46967C9.32322 5.76256 9.32322 6.23744 9.03033 6.53033L5.03033 10.5303C4.73744 10.8232 4.26256 10.8232 3.96967 10.5303C3.67678 10.2374 3.67678 9.76256 3.96967 9.46967L7.43934 6L3.96967 2.53033C3.67678 2.23744 3.67678 1.76256 3.96967 1.46967Z" fill="currentColor"/>
28011
+ </svg>
28012
+ </div>
28013
+ ` }
28011
28014
  </div>
28012
28015
  ` }
28013
28016
  </li>
@@ -28063,7 +28066,7 @@
28063
28066
  const selectedEl = containerEl.querySelector('.selected');
28064
28067
 
28065
28068
  if (selectedEl) {
28066
- scrollIntoView(selectedEl);
28069
+ scrollIntoView$1(selectedEl);
28067
28070
  }
28068
28071
  }, [ selectedEntry ]);
28069
28072
 
@@ -28137,7 +28140,7 @@
28137
28140
  return `${ idPrefix }-group-${ group.id }`;
28138
28141
  }
28139
28142
 
28140
- function scrollIntoView(el) {
28143
+ function scrollIntoView$1(el) {
28141
28144
  if (typeof el.scrollIntoViewIfNeeded === 'function') {
28142
28145
  el.scrollIntoViewIfNeeded();
28143
28146
  } else {
@@ -28179,6 +28182,7 @@
28179
28182
  * @param {PopupMenuEmptyPlaceholder} [props.emptyPlaceholder]
28180
28183
  * @param {number|string} [props.width]
28181
28184
  * @param {searchFn} props.searchFn
28185
+ * @param {import('./PopupMenuProvider.js').PopupMenuTab} [props.defaultTab]
28182
28186
  */
28183
28187
  function PopupMenuComponent(props) {
28184
28188
  const {
@@ -28195,7 +28199,8 @@
28195
28199
  searchFn,
28196
28200
  entries,
28197
28201
  onOpened,
28198
- onClosed
28202
+ onClosed,
28203
+ defaultTab
28199
28204
  } = props;
28200
28205
 
28201
28206
  /**
@@ -28210,12 +28215,183 @@
28210
28215
 
28211
28216
  /**
28212
28217
  * On `PopupMenu#refresh()` (i.e. when `entries` change)
28213
- * the stack is reset to root.
28218
+ * the stack and active tab are reset to root.
28214
28219
  */
28215
28220
  y(() => {
28216
28221
  setNavigationStack([]);
28222
+ setActiveTab(null);
28217
28223
  }, [ entries ]);
28218
28224
 
28225
+ /**
28226
+ * Tabs partition root-level entries. They are derived from the entries'
28227
+ * `tab` property; entries without a `tab` belong to the default tab. The
28228
+ * tab strip only renders when at least two distinct tabs exist.
28229
+ *
28230
+ * @type {import('./PopupMenuProvider.js').PopupMenuTab[]}
28231
+ */
28232
+ const tabs = T(() => {
28233
+ const tabbed = [];
28234
+ const seen = new Set();
28235
+
28236
+ let hasUntagged = false;
28237
+
28238
+ entries.forEach(({ tab }) => {
28239
+ if (!tab) {
28240
+ hasUntagged = true;
28241
+
28242
+ return;
28243
+ }
28244
+
28245
+ if (!seen.has(tab.id)) {
28246
+ seen.add(tab.id);
28247
+ tabbed.push(tab);
28248
+ }
28249
+ });
28250
+
28251
+ if (!tabbed.length) {
28252
+ return [];
28253
+ }
28254
+
28255
+ // untagged entries need a tab to live in; without a configured
28256
+ // `defaultTab` there is no name to give it, so stay untabbed rather
28257
+ // than invent one
28258
+ if (hasUntagged && !defaultTab) {
28259
+ return [];
28260
+ }
28261
+
28262
+ if (!hasUntagged) {
28263
+ return tabbed;
28264
+ }
28265
+
28266
+ return [
28267
+ defaultTab,
28268
+ ...tabbed.filter(tab => tab.id !== defaultTab.id)
28269
+ ];
28270
+ }, [ entries, defaultTab ]);
28271
+
28272
+ const [ activeTabOverride, setActiveTab ] = d(null);
28273
+
28274
+ // the override may name a tab that no longer exists, e.g. on the render
28275
+ // following a `PopupMenu#refresh()` that dropped it
28276
+ const activeTabId = tabs.some(tab => tab.id === activeTabOverride)
28277
+ ? activeTabOverride
28278
+ : (tabs.length ? tabs[0].id : null);
28279
+
28280
+ const tabsRef = A();
28281
+
28282
+ _(() => {
28283
+ const tabsEl = tabsRef.current;
28284
+
28285
+ if (!tabsEl) {
28286
+ return;
28287
+ }
28288
+
28289
+ const activeTabEl = tabsEl.querySelector('[aria-selected="true"]');
28290
+
28291
+ if (activeTabEl) {
28292
+ scrollIntoView(activeTabEl);
28293
+ }
28294
+ }, [ activeTabId ]);
28295
+
28296
+ /**
28297
+ * Which directions the tab strip can still be scrolled in. Drives the
28298
+ * scroll controls, so they only show when there is somewhere to scroll.
28299
+ *
28300
+ * @type {[ { start: boolean, end: boolean }, (overflow: { start: boolean, end: boolean }) => void ]}
28301
+ */
28302
+ const [ overflow, setOverflow ] = d({ start: false, end: false });
28303
+
28304
+ // only ever called while the strip is rendered, so the ref is set
28305
+ const updateOverflow = q(() => {
28306
+ const { scrollLeft, scrollWidth, clientWidth } = tabsRef.current;
28307
+
28308
+ setOverflow({
28309
+ start: scrollLeft > 0,
28310
+
28311
+ // sub-pixel widths leave a fractional remainder at the end
28312
+ end: scrollWidth - clientWidth - scrollLeft > 1
28313
+ });
28314
+ }, []);
28315
+
28316
+ // horizontal scroll on tabs
28317
+ const handleWheel = q(event => {
28318
+ const tabsEl = tabsRef.current;
28319
+
28320
+ const delta = Math.abs(event.deltaX) > Math.abs(event.deltaY)
28321
+ ? event.deltaX
28322
+ : event.deltaY;
28323
+
28324
+ if (!delta) {
28325
+ return;
28326
+ }
28327
+
28328
+ const { scrollLeft, scrollWidth, clientWidth } = tabsEl;
28329
+
28330
+ if (scrollWidth - clientWidth < 1) {
28331
+ return;
28332
+ }
28333
+
28334
+ event.preventDefault();
28335
+
28336
+ tabsEl.scrollLeft = scrollLeft + delta;
28337
+
28338
+ updateOverflow();
28339
+ }, [ updateOverflow ]);
28340
+
28341
+ _(() => {
28342
+ const tabsEl = tabsRef.current;
28343
+
28344
+ if (!tabsEl) {
28345
+ return;
28346
+ }
28347
+
28348
+ updateOverflow();
28349
+
28350
+ tabsEl.addEventListener('scroll', updateOverflow);
28351
+ tabsEl.addEventListener('wheel', handleWheel, { passive: false });
28352
+
28353
+ return () => {
28354
+ tabsEl.removeEventListener('scroll', updateOverflow);
28355
+ tabsEl.removeEventListener('wheel', handleWheel);
28356
+ };
28357
+ }, [ tabs, activeTabId, updateOverflow, handleWheel ]);
28358
+
28359
+ /**
28360
+ * Scroll the nearest tab that is cut off in `direction` into view, so a
28361
+ * click always lands on a fully visible tab.
28362
+ *
28363
+ * @param {number} direction
28364
+ */
28365
+ const scrollTabs = q(direction => {
28366
+ const tabsEl = tabsRef.current;
28367
+
28368
+ const tabEls = direction > 0
28369
+ ? [ ...tabsEl.children ]
28370
+ : [ ...tabsEl.children ].reverse();
28371
+
28372
+ const stripBounds = tabsEl.getBoundingClientRect();
28373
+
28374
+ const cutOff = tabEls.find(tabEl => {
28375
+ const bounds = tabEl.getBoundingClientRect();
28376
+
28377
+ return direction > 0
28378
+ ? bounds.right > stripBounds.right + 1
28379
+ : bounds.left < stripBounds.left - 1;
28380
+ });
28381
+
28382
+ if (cutOff) {
28383
+ scrollIntoView(cutOff);
28384
+
28385
+ // recompute directly: a programmatic scroll does not reliably emit a
28386
+ // `scroll` event, so the controls would otherwise go stale
28387
+ updateOverflow();
28388
+ }
28389
+ }, [ updateOverflow ]);
28390
+
28391
+ const getEntryTabId = q(entry => {
28392
+ return (entry.tab && entry.tab.id) || (defaultTab && defaultTab.id);
28393
+ }, [ defaultTab ]);
28394
+
28219
28395
  const [ searchValue, setSearchValue ] = d('');
28220
28396
  const isSearching = searchValue.trim().length > 0;
28221
28397
 
@@ -28231,9 +28407,15 @@
28231
28407
 
28232
28408
  const entriesToShow = T(() => {
28233
28409
 
28410
+ // the tab filter applies at the root level only; drill-down
28411
+ // (step entries) and search operate on the full entry set
28234
28412
  const availableEntries = navigationStack.length
28235
28413
  ? navigationStack[navigationStack.length - 1].entries
28236
- : entries;
28414
+ : (
28415
+ tabs.length > 1
28416
+ ? entries.filter(entry => getEntryTabId(entry) === activeTabId)
28417
+ : entries
28418
+ );
28237
28419
 
28238
28420
  if (!searchable) return availableEntries;
28239
28421
 
@@ -28246,7 +28428,7 @@
28246
28428
  }
28247
28429
 
28248
28430
  return availableEntries.filter(({ rank = 0 }) => rank >= 0);
28249
- }, [ searchable, isSearching, actionableEntries, searchValue, searchFn, navigationStack, entries ]);
28431
+ }, [ searchable, isSearching, actionableEntries, searchValue, searchFn, navigationStack, entries, tabs, activeTabId, getEntryTabId ]);
28250
28432
 
28251
28433
  const groupedEntries = T(() => {
28252
28434
  if (isSearching) {
@@ -28387,6 +28569,77 @@
28387
28569
  }
28388
28570
  }, [ selectedEntry, keyboardSelect, keyboardDrilldown, handleEntryAction ]);
28389
28571
 
28572
+ const selectTab = q((event, tabId) => {
28573
+ setActiveTab(tabId);
28574
+
28575
+ // a keyboard activation reports no click detail; keep focus in the strip
28576
+ // so arrow navigation keeps working. A pointer click hands focus back to
28577
+ // the search input so typing continues to work
28578
+ if (!event.detail) {
28579
+ return;
28580
+ }
28581
+
28582
+ const popupEl = closest(event.currentTarget, '.djs-popup', true);
28583
+ const inputEl = popupEl && popupEl.querySelector('input');
28584
+
28585
+ inputEl && inputEl.focus();
28586
+ }, []);
28587
+
28588
+ // left/right/Home/End navigate between tabs while the strip has focus; stop
28589
+ // propagation so the global drill-down and entry-action bindings do not fire.
28590
+ // Up/down leave the strip instead
28591
+ const handleTabKeyDown = q(event => {
28592
+ if (event.key === 'Enter' || event.key === ' ') {
28593
+
28594
+ // let the button's native click happen, but keep the event
28595
+ // from reaching the global Enter handler (entry action)
28596
+ event.stopPropagation();
28597
+
28598
+ return;
28599
+ }
28600
+
28601
+ // <ArrowDown> / <ArrowUp> hand focus to the panel so the menu's own
28602
+ // bindings take over — notably <ArrowRight> to step into an entry, which
28603
+ // would otherwise keep switching tabs. The event still bubbles, so the
28604
+ // selection moves on the same keystroke
28605
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
28606
+ const popupEl = closest(event.currentTarget, '.djs-popup', true);
28607
+
28608
+ const focusEl = popupEl.querySelector('input')
28609
+ || popupEl.querySelector('[role="listbox"]');
28610
+
28611
+ focusEl && focusEl.focus();
28612
+
28613
+ return;
28614
+ }
28615
+
28616
+ const idx = tabs.findIndex(tab => tab.id === activeTabId);
28617
+
28618
+ let nextIdx;
28619
+
28620
+ if (event.key === 'ArrowLeft') {
28621
+ nextIdx = (idx - 1 + tabs.length) % tabs.length;
28622
+ } else if (event.key === 'ArrowRight') {
28623
+ nextIdx = (idx + 1) % tabs.length;
28624
+ } else if (event.key === 'Home') {
28625
+ nextIdx = 0;
28626
+ } else if (event.key === 'End') {
28627
+ nextIdx = tabs.length - 1;
28628
+ } else {
28629
+ return;
28630
+ }
28631
+
28632
+ event.preventDefault();
28633
+ event.stopPropagation();
28634
+
28635
+ setActiveTab(tabs[nextIdx].id);
28636
+
28637
+ const strip = event.currentTarget.parentNode;
28638
+ const nextButton = strip && strip.children[nextIdx];
28639
+
28640
+ nextButton && nextButton.focus();
28641
+ }, [ tabs, activeTabId ]);
28642
+
28390
28643
  const handleKey = q(event => {
28391
28644
  if (matches(event.target, 'input')) {
28392
28645
  setSearchValue(() => event.target.value);
@@ -28402,6 +28655,7 @@
28402
28655
  }, []);
28403
28656
 
28404
28657
  const displayBreadcrumbs = !isSearching && navigationStack.length > 0;
28658
+ const displayTabs = tabs.length > 1 && !isSearching && navigationStack.length === 0;
28405
28659
  const displayHeader = (title || headerEntries.length > 0) && !displayBreadcrumbs;
28406
28660
 
28407
28661
  return m$1`
@@ -28451,6 +28705,43 @@
28451
28705
  </div>
28452
28706
  ` }
28453
28707
 
28708
+ ${ displayTabs && m$1`
28709
+ <div class="djs-popup-tabs-container">
28710
+ <div class="djs-popup-tabs" ref=${ tabsRef } role="tablist">
28711
+ ${ tabs.map(tab => m$1`
28712
+ <button
28713
+ type="button"
28714
+ class="djs-popup-tab"
28715
+ role="tab"
28716
+ title=${ tab.title || undefined }
28717
+ aria-controls=${ resultsId }
28718
+ aria-selected=${ tab.id === activeTabId }
28719
+ tabIndex=${ tab.id === activeTabId ? 0 : -1 }
28720
+ onClick=${ (event) => selectTab(event, tab.id) }
28721
+ onKeydown=${ handleTabKeyDown }
28722
+ >${ tab.label }</button>
28723
+ `) }
28724
+ </div>
28725
+
28726
+ ${ /* outside the tablist: its children must be tabs. Keyboard
28727
+ users navigate with the arrow keys instead */ '' }
28728
+ ${ [ -1, 1 ].map(direction => (direction < 0 ? overflow.start : overflow.end) && m$1`
28729
+ <button
28730
+ type="button"
28731
+ class=${ `djs-popup-tabs-scroll djs-popup-tabs-scroll-${ direction < 0 ? 'start' : 'end' }` }
28732
+ aria-hidden="true"
28733
+ tabIndex="-1"
28734
+ onMousedown=${ (event) => event.preventDefault() }
28735
+ onClick=${ () => scrollTabs(direction) }
28736
+ >
28737
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
28738
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M3.96967 1.46967C4.26256 1.17678 4.73744 1.17678 5.03033 1.46967L9.03033 5.46967C9.32322 5.76256 9.32322 6.23744 9.03033 6.53033L5.03033 10.5303C4.73744 10.8232 4.26256 10.8232 3.96967 10.5303C3.67678 10.2374 3.67678 9.76256 3.96967 9.46967L7.43934 6L3.96967 2.53033C3.67678 2.23744 3.67678 1.76256 3.96967 1.46967Z" fill="currentColor"/>
28739
+ </svg>
28740
+ </button>
28741
+ `) }
28742
+ </div>
28743
+ ` }
28744
+
28454
28745
  ${ isSearching && m$1`
28455
28746
  <div class="djs-popup-search-count" aria-live="polite">
28456
28747
  ${ entriesToShow.length } ${ entriesToShow.length === 1 ? 'result' : 'results' } found
@@ -28497,6 +28788,18 @@
28497
28788
  `;
28498
28789
  }
28499
28790
 
28791
+ function scrollIntoView(el) {
28792
+ if (typeof el.scrollIntoViewIfNeeded === 'function') {
28793
+ el.scrollIntoViewIfNeeded();
28794
+ } else {
28795
+ el.scrollIntoView({
28796
+ scrollMode: 'if-needed',
28797
+ block: 'nearest',
28798
+ inline: 'nearest'
28799
+ });
28800
+ }
28801
+ }
28802
+
28500
28803
  /**
28501
28804
  * A component that wraps the popup menu.
28502
28805
  *
@@ -28693,11 +28996,14 @@
28693
28996
  *
28694
28997
  * @typedef {import('../../model/Types.js').Element} Element
28695
28998
  *
28999
+ * @typedef {import('./PopupMenuProvider.js').PopupMenuTab} PopupMenuTab
29000
+ *
28696
29001
  * @typedef { {
28697
29002
  * scale?: {
28698
29003
  * min?: number;
28699
29004
  * max?: number;
28700
29005
  * } | boolean;
29006
+ * defaultTab?: PopupMenuTab;
28701
29007
  * } } PopupMenuConfig
28702
29008
  *
28703
29009
  * @typedef {Element|Element[]} PopupMenuTarget;
@@ -28734,7 +29040,8 @@
28734
29040
  };
28735
29041
 
28736
29042
  this._config = {
28737
- scale: scale
29043
+ scale: scale,
29044
+ defaultTab: config && config.defaultTab
28738
29045
  };
28739
29046
 
28740
29047
 
@@ -28800,6 +29107,7 @@
28800
29107
  onOpened=${ this._onOpened.bind(this) }
28801
29108
  onClosed=${ this._onClosed.bind(this) }
28802
29109
  searchFn=${ this._search }
29110
+ defaultTab=${ this._config.defaultTab }
28803
29111
  ...${{ ...options }}
28804
29112
  />
28805
29113
  `,
@@ -29804,7 +30112,7 @@
29804
30112
  * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').default<Element>} ContextPadProvider
29805
30113
  */
29806
30114
 
29807
- var LOW_PRIORITY$m = 900;
30115
+ var LOW_PRIORITY$o = 900;
29808
30116
 
29809
30117
  /**
29810
30118
  * A provider for the `Align elements` context pad entry.
@@ -29818,7 +30126,7 @@
29818
30126
  */
29819
30127
  function AlignElementsContextPadProvider(contextPad, popupMenu, translate, canvas) {
29820
30128
 
29821
- contextPad.registerProvider(LOW_PRIORITY$m, this);
30129
+ contextPad.registerProvider(LOW_PRIORITY$o, this);
29822
30130
 
29823
30131
  this._contextPad = contextPad;
29824
30132
  this._popupMenu = popupMenu;
@@ -30448,7 +30756,7 @@
30448
30756
  * @typedef {import('../modeling/Modeling.js').default} Modeling
30449
30757
  */
30450
30758
 
30451
- var LOW_PRIORITY$l = 100;
30759
+ var LOW_PRIORITY$n = 100;
30452
30760
 
30453
30761
 
30454
30762
  /**
@@ -30461,7 +30769,7 @@
30461
30769
  */
30462
30770
  function AutoPlace$1(eventBus, modeling, canvas) {
30463
30771
 
30464
- eventBus.on('autoPlace', LOW_PRIORITY$l, function(context) {
30772
+ eventBus.on('autoPlace', LOW_PRIORITY$n, function(context) {
30465
30773
  var shape = context.shape,
30466
30774
  source = context.source;
30467
30775
 
@@ -31324,7 +31632,7 @@
31324
31632
  * @typedef {import('../../core/EventBus.js').default} EventBus
31325
31633
  */
31326
31634
 
31327
- var HIGH_PRIORITY$l = 1500;
31635
+ var HIGH_PRIORITY$m = 1500;
31328
31636
 
31329
31637
 
31330
31638
  /**
@@ -31392,7 +31700,7 @@
31392
31700
  */
31393
31701
  eventBus.on('drag.start', function(event) {
31394
31702
 
31395
- eventBus.once('drag.move', HIGH_PRIORITY$l, function(event) {
31703
+ eventBus.once('drag.move', HIGH_PRIORITY$m, function(event) {
31396
31704
 
31397
31705
  ensureHover(event);
31398
31706
 
@@ -31423,7 +31731,7 @@
31423
31731
  hover = event.element;
31424
31732
  });
31425
31733
 
31426
- eventBus.on('element.hover', HIGH_PRIORITY$l, function(event) {
31734
+ eventBus.on('element.hover', HIGH_PRIORITY$m, function(event) {
31427
31735
 
31428
31736
  // (3) am I on an element still?
31429
31737
  if (hover) {
@@ -33402,7 +33710,7 @@
33402
33710
  MARKER_CONNECT_UPDATING$1 = 'djs-updating',
33403
33711
  MARKER_DRAGGER = 'djs-dragging';
33404
33712
 
33405
- var HIGH_PRIORITY$k = 1100;
33713
+ var HIGH_PRIORITY$l = 1100;
33406
33714
 
33407
33715
  /**
33408
33716
  * Preview connection while moving bendpoints.
@@ -33470,7 +33778,7 @@
33470
33778
  eventBus.on([
33471
33779
  'bendpoint.move.out',
33472
33780
  'bendpoint.move.cleanup'
33473
- ], HIGH_PRIORITY$k, function(event) {
33781
+ ], HIGH_PRIORITY$l, function(event) {
33474
33782
  var context = event.context,
33475
33783
  hover = context.hover,
33476
33784
  target = context.target;
@@ -33556,7 +33864,7 @@
33556
33864
  eventBus.on([
33557
33865
  'bendpoint.move.end',
33558
33866
  'bendpoint.move.cancel'
33559
- ], HIGH_PRIORITY$k, function(event) {
33867
+ ], HIGH_PRIORITY$l, function(event) {
33560
33868
  var context = event.context,
33561
33869
  connection = context.connection,
33562
33870
  draggerGfx = context.draggerGfx,
@@ -34572,8 +34880,8 @@
34572
34880
  * @typedef {import('../../core/EventBus.js').default} EventBus
34573
34881
  */
34574
34882
 
34575
- var HIGH_PRIORITY$j = 1100,
34576
- LOW_PRIORITY$k = 900;
34883
+ var HIGH_PRIORITY$k = 1100,
34884
+ LOW_PRIORITY$m = 900;
34577
34885
 
34578
34886
  var MARKER_OK$3 = 'connect-ok',
34579
34887
  MARKER_NOT_OK$3 = 'connect-not-ok';
@@ -34617,7 +34925,7 @@
34617
34925
  });
34618
34926
  });
34619
34927
 
34620
- eventBus.on('connect.hover', LOW_PRIORITY$k, function(event) {
34928
+ eventBus.on('connect.hover', LOW_PRIORITY$m, function(event) {
34621
34929
  var context = event.context,
34622
34930
  hover = event.hover,
34623
34931
  canExecute = context.canExecute;
@@ -34633,7 +34941,7 @@
34633
34941
  eventBus.on([
34634
34942
  'connect.out',
34635
34943
  'connect.cleanup'
34636
- ], HIGH_PRIORITY$j, function(event) {
34944
+ ], HIGH_PRIORITY$k, function(event) {
34637
34945
  var hover = event.hover;
34638
34946
 
34639
34947
  if (hover) {
@@ -35685,7 +35993,7 @@
35685
35993
  * @typedef {import('../../../model/Types').Element} Element
35686
35994
  */
35687
35995
 
35688
- var HIGH_PRIORITY$i = 1500;
35996
+ var HIGH_PRIORITY$j = 1500;
35689
35997
 
35690
35998
  /**
35691
35999
  * A behavior that ensures that visually enclosed artifacts are affected
@@ -35706,7 +36014,7 @@
35706
36014
  injector.invoke(CommandInterceptor, this);
35707
36015
 
35708
36016
  // enclosed artifacts are deleted with a container element
35709
- this.preExecute('elements.delete', HIGH_PRIORITY$i, function(event) {
36017
+ this.preExecute('elements.delete', HIGH_PRIORITY$j, function(event) {
35710
36018
  var context = event.context,
35711
36019
  elements = context.elements;
35712
36020
 
@@ -35819,7 +36127,7 @@
35819
36127
  * @typedef {import('didi').Injector} Injector
35820
36128
  */
35821
36129
 
35822
- var LOW_PRIORITY$j = 500;
36130
+ var LOW_PRIORITY$l = 500;
35823
36131
 
35824
36132
 
35825
36133
  /**
@@ -35835,7 +36143,7 @@
35835
36143
 
35836
36144
  var self = this;
35837
36145
 
35838
- this.postExecuted('elements.create', LOW_PRIORITY$j, function(context) {
36146
+ this.postExecuted('elements.create', LOW_PRIORITY$l, function(context) {
35839
36147
  var elements = context.elements;
35840
36148
 
35841
36149
  elements = elements.filter(function(shape) {
@@ -35858,7 +36166,7 @@
35858
36166
  }, true);
35859
36167
 
35860
36168
 
35861
- this.preExecute('elements.move', LOW_PRIORITY$j, function(context) {
36169
+ this.preExecute('elements.move', LOW_PRIORITY$l, function(context) {
35862
36170
  var shapes = context.shapes,
35863
36171
  host = context.newHost;
35864
36172
 
@@ -35976,6 +36284,255 @@
35976
36284
 
35977
36285
  e$3(BoundaryEventBehavior, CommandInterceptor);
35978
36286
 
36287
+ /**
36288
+ * @typedef {import('../../BpmnFactory').default} BpmnFactory
36289
+ *
36290
+ * @typedef {import('../../../../model/Types').ModdleElement} ModdleElement
36291
+ */
36292
+
36293
+ /**
36294
+ * Creates a new bpmn:CategoryValue inside a new bpmn:Category
36295
+ *
36296
+ * @param {BpmnFactory} bpmnFactory
36297
+ *
36298
+ * @return {ModdleElement}
36299
+ */
36300
+ function createCategory(bpmnFactory) {
36301
+ return bpmnFactory.create('bpmn:Category');
36302
+ }
36303
+
36304
+ /**
36305
+ * Creates a new bpmn:CategoryValue inside a new bpmn:Category
36306
+ *
36307
+ * @param {BpmnFactory} bpmnFactory
36308
+ *
36309
+ * @return {ModdleElement}
36310
+ */
36311
+ function createCategoryValue(bpmnFactory) {
36312
+ return bpmnFactory.create('bpmn:CategoryValue');
36313
+ }
36314
+
36315
+ /**
36316
+ * Returns a group's category value, creating one (including a
36317
+ * category) if needed.
36318
+ *
36319
+ * @param {BpmnFactory} bpmnFactory
36320
+ * @param {ModdleElement} groupBo
36321
+ *
36322
+ * @return {ModdleElement}
36323
+ */
36324
+ function getOrCreateCategoryValueForGroup(bpmnFactory, groupBo) {
36325
+ var categoryValue = groupBo.get('categoryValueRef');
36326
+
36327
+ if (!categoryValue) {
36328
+ categoryValue = groupBo.categoryValueRef = createCategoryValue(bpmnFactory);
36329
+ }
36330
+
36331
+ if (!categoryValue.$parent) {
36332
+ categoryValue.$parent = createCategory(bpmnFactory);
36333
+ }
36334
+
36335
+ return categoryValue;
36336
+ }
36337
+
36338
+ /**
36339
+ * Adds category value to definitions
36340
+ *
36341
+ * @param {ModdleElement} categoryValue
36342
+ * @param {ModdleElement} category
36343
+ * @param {ModdleElement} definitions
36344
+ *
36345
+ * @return {ModdleElement}
36346
+ */
36347
+ function linkCategoryValue(categoryValue, category, definitions) {
36348
+ add(category.get('categoryValue'), categoryValue);
36349
+ categoryValue.$parent = category;
36350
+
36351
+ add(definitions.get('rootElements'), category);
36352
+ category.$parent = definitions;
36353
+
36354
+ return categoryValue;
36355
+ }
36356
+
36357
+ /**
36358
+ * Unlink category value from parent
36359
+ *
36360
+ * @param {ModdleElement} categoryValue
36361
+ *
36362
+ * @return {ModdleElement}
36363
+ */
36364
+ function unlinkCategoryValue(categoryValue) {
36365
+ var category = categoryValue.$parent;
36366
+
36367
+ if (category) {
36368
+ remove(category.get('categoryValue'), categoryValue);
36369
+ categoryValue.$parent = null;
36370
+ }
36371
+
36372
+ return categoryValue;
36373
+ }
36374
+
36375
+ /**
36376
+ * Unlink category from parent
36377
+ *
36378
+ * @param {ModdleElement} category
36379
+ *
36380
+ * @return {ModdleElement}
36381
+ */
36382
+ function unlinkCategory(category) {
36383
+ var definitions = category.$parent;
36384
+
36385
+ if (definitions) {
36386
+ remove(definitions.get('rootElements'), category);
36387
+ category.$parent = null;
36388
+ }
36389
+
36390
+ return category;
36391
+ }
36392
+
36393
+ var LOW_PRIORITY$k = 500;
36394
+
36395
+ /**
36396
+ * @typedef {import('../../../Modeler').default} Modeler
36397
+ * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
36398
+ * @typedef {import('didi').Injector} Injector
36399
+ */
36400
+
36401
+ /**
36402
+ * Maintains a group's category (value) inside definitions#rootElements.
36403
+ *
36404
+ * @param {Modeler} bpmnjs
36405
+ * @param {ElementRegistry} elementRegistry
36406
+ * @param {Injector} injector
36407
+ */
36408
+ function CategoryRootElementReferenceBehavior(
36409
+ bpmnjs, elementRegistry, injector
36410
+ ) {
36411
+ injector.invoke(CommandInterceptor, this);
36412
+
36413
+ function getGroupBusinessObjects(ignoredBusinessObject) {
36414
+ return elementRegistry.filter(function(element) {
36415
+ return is(element, 'bpmn:Group') && !element.labelTarget;
36416
+ }).map(getBusinessObject).filter(function(businessObject) {
36417
+ return businessObject !== ignoredBusinessObject;
36418
+ });
36419
+ }
36420
+
36421
+ function isCategoryValueReferenced(categoryValue, ignoredBusinessObject) {
36422
+ return getGroupBusinessObjects(ignoredBusinessObject).some(function(businessObject) {
36423
+ return businessObject.get('categoryValueRef') === categoryValue;
36424
+ });
36425
+ }
36426
+
36427
+ function isCategoryReferenced(category, ignoredBusinessObject) {
36428
+ return getGroupBusinessObjects(ignoredBusinessObject).some(function(businessObject) {
36429
+ var categoryValue = businessObject.get('categoryValueRef');
36430
+
36431
+ return categoryValue && categoryValue.$parent === category;
36432
+ });
36433
+ }
36434
+
36435
+ function link(categoryValue, category) {
36436
+ if (categoryValue && category) {
36437
+ linkCategoryValue(categoryValue, category, bpmnjs.getDefinitions());
36438
+ }
36439
+ }
36440
+
36441
+ function unlink(categoryValue, category, ignoredBusinessObject) {
36442
+ if (category && !isCategoryReferenced(category, ignoredBusinessObject)) {
36443
+ unlinkCategory(category);
36444
+ }
36445
+
36446
+ if (categoryValue && !isCategoryValueReferenced(categoryValue, ignoredBusinessObject)) {
36447
+ unlinkCategoryValue(categoryValue);
36448
+ }
36449
+ }
36450
+
36451
+
36452
+ this.executed([ 'shape.create', 'label.create' ], function(context) {
36453
+ var shape = context.labelTarget || context.shape;
36454
+
36455
+ if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
36456
+ return;
36457
+ }
36458
+
36459
+ link(context.categoryValue, context.category);
36460
+ }, true);
36461
+
36462
+ this.reverted([ 'shape.create', 'label.create' ], function(context) {
36463
+ var shape = context.labelTarget || context.shape;
36464
+
36465
+ if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
36466
+ return;
36467
+ }
36468
+
36469
+ unlink(context.categoryValue, context.category, getBusinessObject(shape));
36470
+ }, true);
36471
+
36472
+ this.executed([ 'shape.move', 'shape.resize' ], LOW_PRIORITY$k, function(context) {
36473
+ link(context.categoryValue, context.category);
36474
+ }, true);
36475
+
36476
+ this.reverted([ 'shape.move', 'shape.resize' ], function(context) {
36477
+ var shape = context.shape;
36478
+
36479
+ if (context.categoryValue) {
36480
+ unlink(context.categoryValue, context.category, getBusinessObject(shape));
36481
+ }
36482
+ }, true);
36483
+
36484
+ this.executed('group.updateRefs', function(context) {
36485
+ getGroupUpdates(context).forEach(function(update) {
36486
+ link(update.categoryValue, update.category);
36487
+ });
36488
+ }, true);
36489
+
36490
+ this.reverted('group.updateRefs', function(context) {
36491
+ getGroupUpdates(context).forEach(function(update) {
36492
+ unlink(
36493
+ update.categoryValue,
36494
+ update.category,
36495
+ getBusinessObject(update.groupShape)
36496
+ );
36497
+ });
36498
+ }, true);
36499
+
36500
+ this.executed('shape.delete', function(context) {
36501
+ var shape = context.shape;
36502
+
36503
+ if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
36504
+ return;
36505
+ }
36506
+
36507
+ unlink(context.categoryValue, context.category, getBusinessObject(shape));
36508
+ }, true);
36509
+
36510
+ this.reverted('shape.delete', function(context) {
36511
+ var shape = context.shape;
36512
+
36513
+ if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
36514
+ return;
36515
+ }
36516
+
36517
+ link(context.categoryValue, context.category);
36518
+ }, true);
36519
+ }
36520
+
36521
+ CategoryRootElementReferenceBehavior.$inject = [
36522
+ 'bpmnjs',
36523
+ 'elementRegistry',
36524
+ 'injector'
36525
+ ];
36526
+
36527
+ e$3(CategoryRootElementReferenceBehavior, CommandInterceptor);
36528
+
36529
+
36530
+ // helpers //////////
36531
+
36532
+ function getGroupUpdates(context) {
36533
+ return context.updates?.groups || [];
36534
+ }
36535
+
35979
36536
  /**
35980
36537
  * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
35981
36538
  * @typedef {import('../lib/features/modeling/Modeling').default} Modeling
@@ -36272,7 +36829,7 @@
36272
36829
 
36273
36830
  var PARTICIPANT_BORDER_WIDTH = 30;
36274
36831
 
36275
- var HIGH_PRIORITY$h = 2000;
36832
+ var HIGH_PRIORITY$i = 2000;
36276
36833
 
36277
36834
 
36278
36835
  /**
@@ -36289,7 +36846,7 @@
36289
36846
  eventBus.on([
36290
36847
  'create.start',
36291
36848
  'shape.move.start'
36292
- ], HIGH_PRIORITY$h, function(event) {
36849
+ ], HIGH_PRIORITY$i, function(event) {
36293
36850
  var context = event.context,
36294
36851
  shape = context.shape,
36295
36852
  rootElement = canvas.getRootElement();
@@ -36324,7 +36881,7 @@
36324
36881
  });
36325
36882
 
36326
36883
  // force hovering process when creating first participant
36327
- eventBus.on('create.start', HIGH_PRIORITY$h, function(event) {
36884
+ eventBus.on('create.start', HIGH_PRIORITY$i, function(event) {
36328
36885
  var context = event.context,
36329
36886
  shape = context.shape,
36330
36887
  rootElement = canvas.getRootElement(),
@@ -36336,7 +36893,7 @@
36336
36893
  }
36337
36894
 
36338
36895
  if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
36339
- eventBus.on('element.hover', HIGH_PRIORITY$h, ensureHoveringProcess);
36896
+ eventBus.on('element.hover', HIGH_PRIORITY$i, ensureHoveringProcess);
36340
36897
 
36341
36898
  eventBus.once('create.cleanup', function() {
36342
36899
  eventBus.off('element.hover', ensureHoveringProcess);
@@ -36357,7 +36914,7 @@
36357
36914
 
36358
36915
  // when creating mutliple elements through `elements.create` parent must be set to collaboration
36359
36916
  // and passed to `shape.create` as hint
36360
- this.preExecute('elements.create', HIGH_PRIORITY$h, function(context) {
36917
+ this.preExecute('elements.create', HIGH_PRIORITY$i, function(context) {
36361
36918
  var elements = context.elements,
36362
36919
  parent = context.parent,
36363
36920
  participant = findParticipant(elements),
@@ -37293,7 +37850,7 @@
37293
37850
  * @typedef {import('../../space-tool/BpmnSpaceTool').default} SpaceTool
37294
37851
  */
37295
37852
 
37296
- var LOW_PRIORITY$i = 500;
37853
+ var LOW_PRIORITY$j = 500;
37297
37854
 
37298
37855
 
37299
37856
  /**
@@ -37406,7 +37963,7 @@
37406
37963
  /**
37407
37964
  * Adjust sizes of other lanes after lane deletion
37408
37965
  */
37409
- this.postExecuted('shape.delete', LOW_PRIORITY$i, function(event) {
37966
+ this.postExecuted('shape.delete', LOW_PRIORITY$j, function(event) {
37410
37967
 
37411
37968
  var context = event.context,
37412
37969
  hints = context.hints,
@@ -37439,7 +37996,7 @@
37439
37996
  * @typedef {import('didi').Injector} Injector
37440
37997
  */
37441
37998
 
37442
- var LOW_PRIORITY$h = 500;
37999
+ var LOW_PRIORITY$i = 500;
37443
38000
 
37444
38001
 
37445
38002
  /**
@@ -37455,7 +38012,7 @@
37455
38012
 
37456
38013
  var self = this;
37457
38014
 
37458
- this.postExecuted('elements.create', LOW_PRIORITY$h, function(context) {
38015
+ this.postExecuted('elements.create', LOW_PRIORITY$i, function(context) {
37459
38016
  var elements = context.elements;
37460
38017
 
37461
38018
  elements.filter(function(shape) {
@@ -37469,7 +38026,7 @@
37469
38026
  });
37470
38027
  }, true);
37471
38028
 
37472
- this.preExecute('elements.move', LOW_PRIORITY$h, function(context) {
38029
+ this.preExecute('elements.move', LOW_PRIORITY$i, function(context) {
37473
38030
  var shapes = context.shapes,
37474
38031
  newHost = context.newHost;
37475
38032
 
@@ -37842,7 +38399,7 @@
37842
38399
  * @typedef {import('diagram-js/lib/core/Canvas').default} Canvas
37843
38400
  */
37844
38401
 
37845
- var HIGH_PRIORITY$g = 1500;
38402
+ var HIGH_PRIORITY$h = 1500;
37846
38403
  var HIGHEST_PRIORITY = 2000;
37847
38404
 
37848
38405
 
@@ -37864,7 +38421,7 @@
37864
38421
  'shape.move.move',
37865
38422
  'shape.move.out',
37866
38423
  'shape.move.end'
37867
- ], HIGH_PRIORITY$g, function(event) {
38424
+ ], HIGH_PRIORITY$h, function(event) {
37868
38425
  var context = event.context,
37869
38426
  shape = context.shape || event.shape,
37870
38427
  hover = event.hover;
@@ -37896,7 +38453,7 @@
37896
38453
  'global-connect.out',
37897
38454
  'global-connect.end',
37898
38455
  'global-connect.cleanup'
37899
- ], HIGH_PRIORITY$g, function(event) {
38456
+ ], HIGH_PRIORITY$h, function(event) {
37900
38457
  var hover = event.hover;
37901
38458
 
37902
38459
  // ensure connections start/end on bpmn:Participant,
@@ -37910,7 +38467,7 @@
37910
38467
 
37911
38468
  eventBus.on([
37912
38469
  'bendpoint.move.hover'
37913
- ], HIGH_PRIORITY$g, function(event) {
38470
+ ], HIGH_PRIORITY$h, function(event) {
37914
38471
  var context = event.context,
37915
38472
  hover = event.hover,
37916
38473
  type = context.type;
@@ -37926,7 +38483,7 @@
37926
38483
 
37927
38484
  eventBus.on([
37928
38485
  'connect.start'
37929
- ], HIGH_PRIORITY$g, function(event) {
38486
+ ], HIGH_PRIORITY$h, function(event) {
37930
38487
  var context = event.context,
37931
38488
  start = context.start;
37932
38489
 
@@ -37965,101 +38522,12 @@
37965
38522
  'canvas'
37966
38523
  ];
37967
38524
 
37968
- /**
37969
- * @typedef {import('../../BpmnFactory').default} BpmnFactory
37970
- *
37971
- * @typedef {import('../../../model/Types').ModdleElement} ModdleElement
37972
- */
37973
-
37974
- /**
37975
- * Creates a new bpmn:CategoryValue inside a new bpmn:Category
37976
- *
37977
- * @param {BpmnFactory} bpmnFactory
37978
- *
37979
- * @return {ModdleElement}
37980
- */
37981
- function createCategory(bpmnFactory) {
37982
- return bpmnFactory.create('bpmn:Category');
37983
- }
37984
-
37985
- /**
37986
- * Creates a new bpmn:CategoryValue inside a new bpmn:Category
37987
- *
37988
- * @param {BpmnFactory} bpmnFactory
37989
- *
37990
- * @return {ModdleElement}
37991
- */
37992
- function createCategoryValue(bpmnFactory) {
37993
- return bpmnFactory.create('bpmn:CategoryValue');
37994
- }
37995
-
37996
- /**
37997
- * Adds category value to definitions
37998
- *
37999
- * @param {ModdleElement} categoryValue
38000
- * @param {ModdleElement} category
38001
- * @param {ModdleElement} definitions
38002
- *
38003
- * @return {ModdleElement}
38004
- */
38005
- function linkCategoryValue(categoryValue, category, definitions) {
38006
- add(category.get('categoryValue'), categoryValue);
38007
- categoryValue.$parent = category;
38008
-
38009
- add(definitions.get('rootElements'), category);
38010
- category.$parent = definitions;
38011
-
38012
- return categoryValue;
38013
- }
38014
-
38015
- /**
38016
- * Unlink category value from parent
38017
- *
38018
- * @param {ModdleElement} categoryValue
38019
- *
38020
- * @return {ModdleElement}
38021
- */
38022
- function unlinkCategoryValue(categoryValue) {
38023
- var category = categoryValue.$parent;
38024
-
38025
- if (category) {
38026
- remove(category.get('categoryValue'), categoryValue);
38027
- categoryValue.$parent = null;
38028
- }
38029
-
38030
- return categoryValue;
38031
- }
38032
-
38033
- /**
38034
- * Unlink category from parent
38035
- *
38036
- * @param {ModdleElement} category
38037
- *
38038
- * @return {ModdleElement}
38039
- */
38040
- function unlinkCategory(category) {
38041
- var definitions = category.$parent;
38042
-
38043
- if (definitions) {
38044
- remove(definitions.get('rootElements'), category);
38045
- category.$parent = null;
38046
- }
38047
-
38048
- return category;
38049
- }
38050
-
38051
38525
  /**
38052
38526
  * @typedef {import('../BpmnFactory').default} BpmnFactory
38053
- * @typedef {import('../../../Modeler').default} Modeler
38054
- * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
38055
38527
  * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
38528
+ * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
38056
38529
  * @typedef {import('didi').Injector} Injector
38057
38530
  * @typedef {import('../../copy-paste/ModdleCopy').default} ModdleCopy
38058
- *
38059
- * @typedef {import('../../../model/Types').Element} Element
38060
- * @typedef {import('../../../model/Types').Shape} Shape
38061
- *
38062
- * @typedef {import('diagram-js/lib/util/Types').DirectionTRBL} DirectionTRBL
38063
38531
  */
38064
38532
 
38065
38533
  var LOWER_PRIORITY$1 = 770;
@@ -38069,137 +38537,45 @@
38069
38537
  * BPMN specific group behavior.
38070
38538
  *
38071
38539
  * @param {BpmnFactory} bpmnFactory
38072
- * @param {Modeler} bpmnjs
38073
- * @param {ElementRegistry} elementRegistry
38074
38540
  * @param {EventBus} eventBus
38075
38541
  * @param {Injector} injector
38076
38542
  * @param {ModdleCopy} moddleCopy
38077
38543
  */
38078
38544
  function GroupBehavior(
38079
38545
  bpmnFactory,
38080
- bpmnjs,
38081
- elementRegistry,
38082
38546
  eventBus,
38083
38547
  injector,
38084
38548
  moddleCopy
38085
38549
  ) {
38086
38550
  injector.invoke(CommandInterceptor, this);
38087
38551
 
38088
- /**
38089
- * Returns all group element in the current registry.
38090
- *
38091
- * @return {Shape[]}
38092
- */
38093
- function getGroupElements() {
38094
- return elementRegistry.filter(function(e) {
38095
- return is(e, 'bpmn:Group');
38096
- });
38097
- }
38098
-
38099
- /**
38100
- * Returns true if given category is referenced in one of the given elements.
38101
- *
38102
- * @param {Element[]} elements
38103
- * @param {ModdleElement} category
38104
- *
38105
- * @return {boolean}
38106
- */
38107
- function isReferencedCategory(elements, category) {
38108
- return elements.some(function(element) {
38109
- var businessObject = getBusinessObject(element);
38110
-
38111
- var _category = businessObject.categoryValueRef && businessObject.categoryValueRef.$parent;
38112
-
38113
- return _category === category;
38114
- });
38115
- }
38116
-
38117
- /**
38118
- * Returns true if given categoryValue is referenced in one of the given elements.
38119
- *
38120
- * @param {Element[]} elements
38121
- * @param {ModdleElement} categoryValue
38122
- *
38123
- * @return {boolean}
38124
- */
38125
- function isReferencedCategoryValue(elements, categoryValue) {
38126
- return elements.some(function(element) {
38127
- var businessObject = getBusinessObject(element);
38128
-
38129
- return businessObject.categoryValueRef === categoryValue;
38130
- });
38131
- }
38132
-
38133
- /**
38134
- * Remove category value unless it is still referenced.
38135
- *
38136
- * @param {ModdleElement} categoryValue
38137
- * @param {ModdleElement} category
38138
- * @param {ModdleElement} businessObject
38139
- */
38140
- function removeCategoryValue(categoryValue, category, businessObject) {
38141
-
38142
- var groups = getGroupElements().filter(function(element) {
38143
- return element.businessObject !== businessObject;
38144
- });
38145
-
38146
- if (category && !isReferencedCategory(groups, category)) {
38147
- unlinkCategory(category);
38148
- }
38149
-
38150
- if (categoryValue && !isReferencedCategoryValue(groups, categoryValue)) {
38151
- unlinkCategoryValue(categoryValue);
38152
- }
38153
- }
38154
-
38155
- /**
38156
- * Add category value.
38157
- *
38158
- * @param {ModdleElement} categoryValue
38159
- * @param {ModdleElement} category
38160
- *
38161
- * @return {ModdleElement}
38162
- */
38163
- function addCategoryValue(categoryValue, category) {
38164
- return linkCategoryValue(categoryValue, category, bpmnjs.getDefinitions());
38165
- }
38166
-
38167
38552
  function setCategoryValue(element, context) {
38168
38553
  var businessObject = getBusinessObject(element),
38169
- categoryValue = businessObject.categoryValueRef;
38554
+ categoryValue = context.categoryValue || businessObject.categoryValueRef;
38170
38555
 
38171
38556
  if (!categoryValue) {
38172
- categoryValue =
38173
- businessObject.categoryValueRef =
38174
- context.categoryValue = (
38175
- context.categoryValue || createCategoryValue(bpmnFactory)
38176
- );
38557
+ categoryValue = getOrCreateCategoryValueForGroup(bpmnFactory, businessObject);
38177
38558
  }
38178
38559
 
38179
- var category = categoryValue.$parent;
38560
+ var category = context.category || categoryValue.$parent || createCategory(bpmnFactory);
38180
38561
 
38181
- if (!category) {
38182
- category =
38183
- categoryValue.$parent =
38184
- context.category = (
38185
- context.category || createCategory(bpmnFactory)
38186
- );
38187
- }
38562
+ businessObject.categoryValueRef = categoryValue;
38563
+ categoryValue.$parent = category;
38188
38564
 
38189
- addCategoryValue(categoryValue, category, bpmnjs.getDefinitions());
38565
+ context.categoryValue = categoryValue;
38566
+ context.category = category;
38190
38567
  }
38191
38568
 
38192
38569
  function unsetCategoryValue(element, context) {
38193
- var category = context.category,
38194
- categoryValue = context.categoryValue,
38195
- businessObject = getBusinessObject(element);
38570
+ var businessObject = getBusinessObject(element),
38571
+ categoryValue = context.categoryValue || businessObject.categoryValueRef,
38572
+ category = context.category || (categoryValue && categoryValue.$parent);
38196
38573
 
38197
38574
  if (categoryValue) {
38198
- businessObject.categoryValueRef = null;
38575
+ context.categoryValue = categoryValue;
38576
+ context.category = category;
38199
38577
 
38200
- removeCategoryValue(categoryValue, category, businessObject);
38201
- } else {
38202
- removeCategoryValue(null, businessObject.categoryValueRef.$parent, businessObject);
38578
+ businessObject.categoryValueRef = null;
38203
38579
  }
38204
38580
  }
38205
38581
 
@@ -38241,14 +38617,10 @@
38241
38617
  return;
38242
38618
  }
38243
38619
 
38244
- var categoryValue = context.categoryValue = businessObject.categoryValueRef,
38245
- category;
38620
+ var categoryValue = context.categoryValue = businessObject.categoryValueRef;
38246
38621
 
38247
38622
  if (categoryValue) {
38248
- category = context.category = categoryValue.$parent;
38249
-
38250
- removeCategoryValue(categoryValue, category, businessObject);
38251
-
38623
+ context.category = categoryValue.$parent;
38252
38624
  businessObject.categoryValueRef = null;
38253
38625
  }
38254
38626
  });
@@ -38268,39 +38640,77 @@
38268
38640
 
38269
38641
  if (categoryValue) {
38270
38642
  businessObject.categoryValueRef = categoryValue;
38271
-
38272
- addCategoryValue(categoryValue, category);
38643
+ categoryValue.$parent = category;
38273
38644
  }
38274
38645
  });
38275
38646
 
38276
38647
 
38277
- // create new category + value when group was created
38648
+ // create new category + value when group was created so that visually
38649
+ // enclosed elements can be categorized against it, even if it is unlabeled
38278
38650
 
38279
38651
  this.execute('shape.create', function(event) {
38280
38652
  var context = event.context,
38281
- shape = context.shape;
38653
+ shape = context.shape,
38654
+ hints = context.hints || {};
38282
38655
 
38283
38656
  if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
38284
38657
  return;
38285
38658
  }
38286
38659
 
38287
- if (getBusinessObject(shape).categoryValueRef) {
38288
- setCategoryValue(shape, context);
38660
+ // during paste the category value (if any) is carried over from the
38661
+ // source; only fabricate one for genuinely new groups
38662
+ if (hints.createElementsBehavior === false &&
38663
+ !getBusinessObject(shape).categoryValueRef &&
38664
+ !context.categoryValue) {
38665
+ return;
38289
38666
  }
38667
+
38668
+ setCategoryValue(shape, context);
38290
38669
  });
38291
38670
 
38292
38671
  this.reverted('shape.create', function(event) {
38293
38672
 
38294
38673
  var context = event.context,
38295
- shape = context.shape;
38674
+ shape = context.shape,
38675
+ hints = context.hints || {};
38296
38676
 
38297
38677
  if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
38298
38678
  return;
38299
38679
  }
38300
38680
 
38301
- if (getBusinessObject(shape).categoryValueRef) {
38302
- unsetCategoryValue(shape, context);
38681
+ if (hints.createElementsBehavior === false &&
38682
+ !getBusinessObject(shape).categoryValueRef &&
38683
+ !context.categoryValue) {
38684
+ return;
38685
+ }
38686
+
38687
+ unsetCategoryValue(shape, context);
38688
+ });
38689
+
38690
+
38691
+ // add category -> categoryValue for groups when they change
38692
+
38693
+ this.executed([ 'shape.move', 'shape.resize' ], function(event) {
38694
+ var context = event.context,
38695
+ shape = context.shape;
38696
+
38697
+ if (!is(shape, 'bpmn:Group') || shape.labelTarget ||
38698
+ getBusinessObject(shape).categoryValueRef) {
38699
+ return;
38303
38700
  }
38701
+
38702
+ setCategoryValue(shape, context);
38703
+ });
38704
+
38705
+ this.reverted([ 'shape.move', 'shape.resize' ], function(event) {
38706
+ var context = event.context,
38707
+ shape = context.shape;
38708
+
38709
+ if (!is(shape, 'bpmn:Group') || shape.labelTarget || !context.categoryValue) {
38710
+ return;
38711
+ }
38712
+
38713
+ unsetCategoryValue(shape, context);
38304
38714
  });
38305
38715
 
38306
38716
 
@@ -38356,8 +38766,6 @@
38356
38766
 
38357
38767
  GroupBehavior.$inject = [
38358
38768
  'bpmnFactory',
38359
- 'bpmnjs',
38360
- 'elementRegistry',
38361
38769
  'eventBus',
38362
38770
  'injector',
38363
38771
  'moddleCopy'
@@ -40412,7 +40820,7 @@
40412
40820
  'selection'
40413
40821
  ];
40414
40822
 
40415
- var HIGH_PRIORITY$f = 1500;
40823
+ var HIGH_PRIORITY$g = 1500;
40416
40824
 
40417
40825
  /**
40418
40826
  * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
@@ -40465,7 +40873,7 @@
40465
40873
  * @param {EventBus} eventBus
40466
40874
  */
40467
40875
  function ResizeBehavior$1(eventBus) {
40468
- eventBus.on('resize.start', HIGH_PRIORITY$f, function(event) {
40876
+ eventBus.on('resize.start', HIGH_PRIORITY$g, function(event) {
40469
40877
  var context = event.context,
40470
40878
  shape = context.shape,
40471
40879
  direction = context.direction,
@@ -40737,7 +41145,7 @@
40737
41145
  * @typedef {import('diagram-js/lib/util/Types').DirectionTRBL} DirectionTRBL
40738
41146
  */
40739
41147
 
40740
- var LOW_PRIORITY$g = 500;
41148
+ var LOW_PRIORITY$h = 500;
40741
41149
 
40742
41150
 
40743
41151
  /**
@@ -40867,7 +41275,7 @@
40867
41275
  }
40868
41276
  });
40869
41277
 
40870
- eventBus.on('copyPaste.pasteElement', LOW_PRIORITY$g, function(context) {
41278
+ eventBus.on('copyPaste.pasteElement', LOW_PRIORITY$h, function(context) {
40871
41279
  var descriptor = context.descriptor,
40872
41280
  businessObject = descriptor.businessObject,
40873
41281
  referencedRootElement = descriptor.referencedRootElement;
@@ -41112,8 +41520,8 @@
41112
41520
  * @typedef {import('../../../model/Types').ModdleElement} ModdleElement
41113
41521
  */
41114
41522
 
41115
- var LOW_PRIORITY$f = 400;
41116
- var HIGH_PRIORITY$e = 600;
41523
+ var LOW_PRIORITY$g = 400;
41524
+ var HIGH_PRIORITY$f = 600;
41117
41525
 
41118
41526
  var DEFAULT_POSITION = {
41119
41527
  x: 180,
@@ -41387,7 +41795,7 @@
41387
41795
 
41388
41796
 
41389
41797
  // create/remove plane for the subprocess
41390
- this.executed('shape.toggleCollapse', LOW_PRIORITY$f, function(context) {
41798
+ this.executed('shape.toggleCollapse', LOW_PRIORITY$g, function(context) {
41391
41799
  var shape = context.shape;
41392
41800
 
41393
41801
  if (!is(shape, 'bpmn:SubProcess')) {
@@ -41405,7 +41813,7 @@
41405
41813
 
41406
41814
 
41407
41815
  // create/remove plane for the subprocess
41408
- this.reverted('shape.toggleCollapse', LOW_PRIORITY$f, function(context) {
41816
+ this.reverted('shape.toggleCollapse', LOW_PRIORITY$g, function(context) {
41409
41817
  var shape = context.shape;
41410
41818
 
41411
41819
  if (!is(shape, 'bpmn:SubProcess')) {
@@ -41422,7 +41830,7 @@
41422
41830
  }, true);
41423
41831
 
41424
41832
  // move elements between planes
41425
- this.postExecuted('shape.toggleCollapse', HIGH_PRIORITY$e, function(context) {
41833
+ this.postExecuted('shape.toggleCollapse', HIGH_PRIORITY$f, function(context) {
41426
41834
  var shape = context.shape;
41427
41835
 
41428
41836
  if (!is(shape, 'bpmn:SubProcess')) {
@@ -41969,7 +42377,7 @@
41969
42377
  * @typedef {import('../Modeling').default} Modeling
41970
42378
  */
41971
42379
 
41972
- var LOW_PRIORITY$e = 500;
42380
+ var LOW_PRIORITY$f = 500;
41973
42381
 
41974
42382
  /**
41975
42383
  * @param {EventBus} eventBus
@@ -42030,7 +42438,7 @@
42030
42438
  };
42031
42439
  }
42032
42440
 
42033
- this.executed([ 'shape.toggleCollapse' ], LOW_PRIORITY$e, function(e) {
42441
+ this.executed([ 'shape.toggleCollapse' ], LOW_PRIORITY$f, function(e) {
42034
42442
 
42035
42443
  var context = e.context,
42036
42444
  shape = context.shape;
@@ -42053,7 +42461,7 @@
42053
42461
  }
42054
42462
  });
42055
42463
 
42056
- this.reverted([ 'shape.toggleCollapse' ], LOW_PRIORITY$e, function(e) {
42464
+ this.reverted([ 'shape.toggleCollapse' ], LOW_PRIORITY$f, function(e) {
42057
42465
 
42058
42466
  var context = e.context;
42059
42467
  var shape = context.shape;
@@ -42068,7 +42476,7 @@
42068
42476
  }
42069
42477
  });
42070
42478
 
42071
- this.postExecuted([ 'shape.toggleCollapse' ], LOW_PRIORITY$e, function(e) {
42479
+ this.postExecuted([ 'shape.toggleCollapse' ], LOW_PRIORITY$f, function(e) {
42072
42480
  var shape = e.context.shape,
42073
42481
  defaultSize = elementFactory.getDefaultSize(shape),
42074
42482
  newBounds;
@@ -42223,12 +42631,31 @@
42223
42631
  * @typedef {import('../Modeling').default} Modeling
42224
42632
  */
42225
42633
 
42226
- var LOW_PRIORITY$d = 500,
42227
- HIGH_PRIORITY$d = 5000;
42634
+ var LOW_PRIORITY$e = 500,
42635
+ HIGH_PRIORITY$e = 5000;
42636
+
42637
+ // Commands that provide a shape whose lane references must be updated.
42638
+ var laneRefShapeEvents = [
42639
+ 'shape.create',
42640
+ 'shape.delete',
42641
+ 'shape.move',
42642
+ 'shape.resize'
42643
+ ];
42228
42644
 
42645
+ // Commands that bracket a complete lane reference update, including nested commands.
42646
+ var laneRefUpdateEvents = [
42647
+ ...laneRefShapeEvents,
42648
+ 'spaceTool',
42649
+ 'lane.add',
42650
+ 'lane.resize',
42651
+ 'lane.split',
42652
+ 'elements.create',
42653
+ 'elements.delete',
42654
+ 'elements.move'
42655
+ ];
42229
42656
 
42230
42657
  /**
42231
- * BPMN specific delete lane behavior.
42658
+ * Synchronizes lane flow node references after geometry changes.
42232
42659
  *
42233
42660
  * @param {EventBus} eventBus
42234
42661
  * @param {Modeling} modeling
@@ -42237,18 +42664,11 @@
42237
42664
 
42238
42665
  CommandInterceptor.call(this, eventBus);
42239
42666
 
42240
- /**
42241
- * Update Lane#flowNodeRefs and FlowNode#lanes with every flow node
42242
- * move/resize and lane move/resize. Groups elements to recompute containments
42243
- * as efficient as possible.
42244
- */
42245
-
42246
- // the update context
42247
42667
  var context;
42248
42668
 
42249
42669
 
42250
42670
  function initContext() {
42251
- context = context || new UpdateContext();
42671
+ context = context || new UpdateContext$1();
42252
42672
  context.enter();
42253
42673
 
42254
42674
  return context;
@@ -42280,40 +42700,26 @@
42280
42700
  }
42281
42701
 
42282
42702
 
42283
- var laneRefUpdateEvents = [
42284
- 'spaceTool',
42285
- 'lane.add',
42286
- 'lane.resize',
42287
- 'lane.split',
42288
- 'elements.create',
42289
- 'elements.delete',
42290
- 'elements.move',
42291
- 'shape.create',
42292
- 'shape.delete',
42293
- 'shape.move',
42294
- 'shape.resize'
42295
- ];
42296
-
42297
-
42298
- // listen to a lot of stuff to group lane updates
42299
-
42300
- this.preExecute(laneRefUpdateEvents, HIGH_PRIORITY$d, function(event) {
42703
+ /**
42704
+ * Sets up the context for lane reference updates before executing commands
42705
+ * that may affect them.
42706
+ */
42707
+ this.preExecute(laneRefUpdateEvents, HIGH_PRIORITY$e, function() {
42301
42708
  initContext();
42302
42709
  });
42303
42710
 
42304
- this.postExecuted(laneRefUpdateEvents, LOW_PRIORITY$d, function(event) {
42711
+ /**
42712
+ * Releases the context for lane reference updates after executing commands
42713
+ * that may affect them.
42714
+ */
42715
+ this.postExecuted(laneRefUpdateEvents, LOW_PRIORITY$e, function() {
42305
42716
  releaseContext();
42306
42717
  });
42307
42718
 
42308
-
42309
- // Mark flow nodes + lanes that need an update
42310
-
42311
- this.preExecute([
42312
- 'shape.create',
42313
- 'shape.move',
42314
- 'shape.delete',
42315
- 'shape.resize'
42316
- ], function(event) {
42719
+ /**
42720
+ * Handles updates to lane references for shapes.
42721
+ */
42722
+ this.preExecute(laneRefShapeEvents, function(event) {
42317
42723
 
42318
42724
  var context = event.context,
42319
42725
  shape = context.shape;
@@ -42321,7 +42727,7 @@
42321
42727
  var updateContext = getContext();
42322
42728
 
42323
42729
  // no need to update labels
42324
- if (shape.labelTarget) {
42730
+ if (!shape || shape.labelTarget) {
42325
42731
  return;
42326
42732
  }
42327
42733
 
@@ -42343,7 +42749,7 @@
42343
42749
  e$3(UpdateFlowNodeRefsBehavior, CommandInterceptor);
42344
42750
 
42345
42751
 
42346
- function UpdateContext() {
42752
+ function UpdateContext$1() {
42347
42753
 
42348
42754
  this.flowNodes = [];
42349
42755
  this.lanes = [];
@@ -42369,6 +42775,168 @@
42369
42775
  };
42370
42776
  }
42371
42777
 
42778
+ /**
42779
+ * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
42780
+ * @typedef {import('../Modeling').default} Modeling
42781
+ */
42782
+
42783
+ var LOW_PRIORITY$d = 500,
42784
+ HIGH_PRIORITY$d = 5000;
42785
+
42786
+ // Commands that provide a shape or connection whose references must be updated.
42787
+ var categoryValueRefShapeAndConnectionEvents = [
42788
+ 'connection.create',
42789
+ 'connection.delete',
42790
+ 'connection.layout',
42791
+ 'connection.move',
42792
+ 'connection.reconnect',
42793
+ 'connection.updateWaypoints',
42794
+ 'shape.create',
42795
+ 'shape.delete',
42796
+ 'shape.move',
42797
+ 'shape.resize'
42798
+ ];
42799
+
42800
+ // Commands that bracket a complete reference update, including nested commands.
42801
+ var categoryValueRefUpdateEvents = [
42802
+ ...categoryValueRefShapeAndConnectionEvents,
42803
+ 'elements.create',
42804
+ 'elements.delete',
42805
+ 'elements.move',
42806
+ 'label.create',
42807
+ 'spaceTool'
42808
+ ];
42809
+
42810
+ /**
42811
+ * Synchronizes group category references after geometry changes.
42812
+ *
42813
+ * @param {EventBus} eventBus
42814
+ * @param {Modeling} modeling
42815
+ */
42816
+ function UpdateCategoryValueRefsBehavior(eventBus, modeling) {
42817
+
42818
+ CommandInterceptor.call(this, eventBus);
42819
+
42820
+ var context;
42821
+
42822
+ function initContext() {
42823
+ context = context || new UpdateContext();
42824
+ context.enter();
42825
+
42826
+ return context;
42827
+ }
42828
+
42829
+ function getContext() {
42830
+ if (!context) {
42831
+ throw new Error('out of bounds release');
42832
+ }
42833
+
42834
+ return context;
42835
+ }
42836
+
42837
+ function releaseContext() {
42838
+ if (!context) {
42839
+ throw new Error('out of bounds release');
42840
+ }
42841
+
42842
+ var triggerUpdate = context.leave();
42843
+
42844
+ if (triggerUpdate) {
42845
+ modeling.updateCategoryValueRefs(
42846
+ Array.from(context.affectedFlowElements),
42847
+ Array.from(context.affectedGroupEntries.values())
42848
+ );
42849
+
42850
+ context = null;
42851
+ }
42852
+
42853
+ return triggerUpdate;
42854
+ }
42855
+
42856
+ /**
42857
+ * Sets up the context for category value reference updates before executing
42858
+ * commands that may affect them.
42859
+ */
42860
+ this.preExecute(categoryValueRefUpdateEvents, HIGH_PRIORITY$d, function() {
42861
+ initContext();
42862
+ });
42863
+
42864
+ /**
42865
+ * Releases the context for category value reference updates after executing
42866
+ * commands that may affect them.
42867
+ */
42868
+ this.postExecuted(categoryValueRefUpdateEvents, LOW_PRIORITY$d, function() {
42869
+ releaseContext();
42870
+ });
42871
+
42872
+ /**
42873
+ * Handles updates to category value references for shapes and connections.
42874
+ */
42875
+ this.preExecute(categoryValueRefShapeAndConnectionEvents, function(event) {
42876
+ var shape = event.context.connection || event.context.shape,
42877
+ updateContext = getContext();
42878
+
42879
+ if (!shape || shape.labelTarget) {
42880
+ return;
42881
+ }
42882
+
42883
+ if (is(shape, 'bpmn:FlowElement')) {
42884
+ updateContext.addFlowElement(shape);
42885
+ }
42886
+
42887
+ if (is(shape, 'bpmn:Group')) {
42888
+ updateContext.addGroup(shape);
42889
+ }
42890
+ });
42891
+
42892
+ this.preExecute('label.create', function(event) {
42893
+ var labelTarget = event.context.labelTarget;
42894
+
42895
+ if (is(labelTarget, 'bpmn:Group')) {
42896
+ getContext().addGroup(labelTarget);
42897
+ }
42898
+ });
42899
+ }
42900
+
42901
+ UpdateCategoryValueRefsBehavior.$inject = [
42902
+ 'eventBus',
42903
+ 'modeling'
42904
+ ];
42905
+
42906
+ e$3(UpdateCategoryValueRefsBehavior, CommandInterceptor);
42907
+
42908
+
42909
+ function UpdateContext() {
42910
+
42911
+ this.affectedFlowElements = new Set();
42912
+ this.affectedGroupEntries = new Map();
42913
+
42914
+ this.counter = 0;
42915
+
42916
+ this.addFlowElement = function(flowElement) {
42917
+ this.affectedFlowElements.add(flowElement);
42918
+ };
42919
+
42920
+ this.addGroup = function(group) {
42921
+ if (!this.affectedGroupEntries.has(group)) {
42922
+ this.affectedGroupEntries.set(group, {
42923
+ categoryValue: group.businessObject.categoryValueRef,
42924
+ groupShape: group
42925
+ });
42926
+ }
42927
+ };
42928
+
42929
+ this.enter = function() {
42930
+ this.counter++;
42931
+ };
42932
+
42933
+ this.leave = function() {
42934
+ this.counter--;
42935
+
42936
+ return !this.counter;
42937
+ };
42938
+ }
42939
+
42372
42940
  /**
42373
42941
  * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
42374
42942
  * @typedef {import('../../rules/BpmnRules').default} BpmnRules
@@ -42440,6 +43008,7 @@
42440
43008
  'associationBehavior',
42441
43009
  'attachEventBehavior',
42442
43010
  'boundaryEventBehavior',
43011
+ 'categoryRootElementReferenceBehavior',
42443
43012
  'compensateBoundaryEventBehaviour',
42444
43013
  'createBehavior',
42445
43014
  'createDataObjectBehavior',
@@ -42474,6 +43043,7 @@
42474
43043
  'toggleElementCollapseBehaviour',
42475
43044
  'unclaimIdBehavior',
42476
43045
  'updateFlowNodeRefsBehavior',
43046
+ 'updateCategoryValueRefsBehavior',
42477
43047
  'unsetDefaultFlowBehavior',
42478
43048
  'setCompensationActivityAfterPasteBehavior'
42479
43049
  ],
@@ -42483,6 +43053,7 @@
42483
43053
  attachEventBehavior: [ 'type', AttachEventBehavior ],
42484
43054
  artifactBehavior: [ 'type', ArtifactBehavior ],
42485
43055
  boundaryEventBehavior: [ 'type', BoundaryEventBehavior ],
43056
+ categoryRootElementReferenceBehavior: [ 'type', CategoryRootElementReferenceBehavior ],
42486
43057
  compensateBoundaryEventBehaviour: [ 'type', CompensateBoundaryEventBehavior ],
42487
43058
  createBehavior: [ 'type', CreateBehavior ],
42488
43059
  createDataObjectBehavior: [ 'type', CreateDataObjectBehavior ],
@@ -42518,6 +43089,7 @@
42518
43089
  unclaimIdBehavior: [ 'type', UnclaimIdBehavior ],
42519
43090
  unsetDefaultFlowBehavior: [ 'type', DeleteSequenceFlowBehavior ],
42520
43091
  updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ],
43092
+ updateCategoryValueRefsBehavior: [ 'type', UpdateCategoryValueRefsBehavior ],
42521
43093
  setCompensationActivityAfterPasteBehavior: [ 'type', SetCompensationActivityAfterPasteBehavior ]
42522
43094
  };
42523
43095
 
@@ -43696,9 +44268,47 @@
43696
44268
  return false;
43697
44269
  }
43698
44270
 
44271
+ // do not copy message flows unless both connected participants are copied,
44272
+ // too; otherwise they would end up in an invalid organizational context
44273
+ if (is(element, 'bpmn:MessageFlow') && !canCopyMessageFlow(elements, element)) {
44274
+ return false;
44275
+ }
44276
+
43699
44277
  return true;
43700
44278
  }
43701
44279
 
44280
+ /**
44281
+ * A message flow may only be copied if both of its participants are copied,
44282
+ * too. Otherwise it would be pasted into an invalid organizational context,
44283
+ * e.g. a plain process.
44284
+ *
44285
+ * @param {Element[]} elements
44286
+ * @param {Connection} connection
44287
+ *
44288
+ * @return {boolean}
44289
+ */
44290
+ function canCopyMessageFlow(elements, connection) {
44291
+ var sourceParticipant = getParticipant(connection.source),
44292
+ targetParticipant = getParticipant(connection.target);
44293
+
44294
+ return includes$2(elements, sourceParticipant) && includes$2(elements, targetParticipant);
44295
+ }
44296
+
44297
+ /**
44298
+ * @param {Element} element
44299
+ *
44300
+ * @return {Element|null}
44301
+ */
44302
+ function getParticipant(element) {
44303
+ for (; element; element = element.parent) {
44304
+ if (is(element, 'bpmn:Participant')) {
44305
+ return element;
44306
+ }
44307
+ }
44308
+
44309
+ return null;
44310
+ }
44311
+
43702
44312
  /**
43703
44313
  * @param {Element} element
43704
44314
  *
@@ -53603,8 +54213,6 @@
53603
54213
  /**
53604
54214
  * @typedef {import('diagram-js/lib/command/CommandHandler').default} CommandHandler
53605
54215
  *
53606
- * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
53607
- *
53608
54216
  * @typedef {import('../../../model/Types').Shape} Shape
53609
54217
  */
53610
54218
 
@@ -53617,15 +54225,9 @@
53617
54225
  *
53618
54226
  * @implements {CommandHandler}
53619
54227
  *
53620
- * @param {ElementRegistry} elementRegistry
53621
54228
  */
53622
- function UpdateFlowNodeRefsHandler(elementRegistry) {
53623
- this._elementRegistry = elementRegistry;
53624
- }
54229
+ function UpdateFlowNodeRefsHandler() {}
53625
54230
 
53626
- UpdateFlowNodeRefsHandler.$inject = [
53627
- 'elementRegistry'
53628
- ];
53629
54231
 
53630
54232
  /**
53631
54233
  * @param {Shape} flowNodeShapes
@@ -53801,6 +54403,409 @@
53801
54403
  return [];
53802
54404
  };
53803
54405
 
54406
+ /**
54407
+ * @typedef {import('diagram-js/lib/command/CommandHandler').default} CommandHandler
54408
+ * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
54409
+ * @typedef {import('../BpmnFactory').default} BpmnFactory
54410
+ *
54411
+ * @typedef {import('../../../model/Types').Element} Element
54412
+ * @typedef {import('../../../model/Types').ModdleElement} ModdleElement
54413
+ *
54414
+ * @typedef { {
54415
+ * categoryValue: ModdleElement;
54416
+ * root?: Element;
54417
+ * } } CategoryGroupEntry
54418
+ */
54419
+
54420
+ var CATEGORY_VALUE_REFS_ATTR = 'categoryValueRef';
54421
+
54422
+
54423
+ /**
54424
+ * Updates category value references for flow elements visually enclosed by groups.
54425
+ *
54426
+ * A flow element is grouped only when it shares the group's diagram root and
54427
+ * is geometrically enclosed by the group. Consequently, visible children of an
54428
+ * expanded subprocess are grouped, while children of a collapsed subprocess
54429
+ * are not.
54430
+ *
54431
+ * Groups without a category value are auto-healed: if such a group visually
54432
+ * encloses an affected flow element a category value is created for it on the
54433
+ * fly, so that legacy diagrams (groups modeled without a category value) start
54434
+ * to categorize their contents as soon as they are interacted with.
54435
+ *
54436
+ * @implements {CommandHandler}
54437
+ *
54438
+ * @param {BpmnFactory} bpmnFactory
54439
+ * @param {ElementRegistry} elementRegistry
54440
+ */
54441
+ function UpdateCategoryValueRefsHandler(bpmnFactory, elementRegistry) {
54442
+ this._bpmnFactory = bpmnFactory;
54443
+ this._elementRegistry = elementRegistry;
54444
+ }
54445
+
54446
+ UpdateCategoryValueRefsHandler.$inject = [
54447
+ 'bpmnFactory',
54448
+ 'elementRegistry'
54449
+ ];
54450
+
54451
+
54452
+ /**
54453
+ * @param { Element[] } affectedFlowElements
54454
+ * @param { {
54455
+ * categoryValue: ModdleElement;
54456
+ * groupShape: Element;
54457
+ * }[] } affectedGroupEntries
54458
+ *
54459
+ * @return { {
54460
+ * flowElements: {
54461
+ * businessObject: ModdleElement;
54462
+ * categoryValuesToAdd: ModdleElement[];
54463
+ * categoryValuesToRemove: ModdleElement[];
54464
+ * }[];
54465
+ * groups: {
54466
+ * groupShape: Element;
54467
+ * categoryValue: ModdleElement;
54468
+ * category: ModdleElement;
54469
+ * }[];
54470
+ * } }
54471
+ */
54472
+ UpdateCategoryValueRefsHandler.prototype._computeUpdates = function(affectedFlowElements, affectedGroupEntries) {
54473
+ var elementRegistry = this._elementRegistry,
54474
+ bpmnFactory = this._bpmnFactory;
54475
+
54476
+ /** @type {Map<Element, ModdleElement>} */
54477
+ var flowElementBusinessObjects = new Map();
54478
+
54479
+ var groupUpdates = [];
54480
+
54481
+ /**
54482
+ * @type {Map<Element, {
54483
+ * present?: CategoryGroupEntry;
54484
+ * past?: CategoryGroupEntry;
54485
+ * }>}
54486
+ */
54487
+ var categoryGroups = new Map();
54488
+
54489
+ /**
54490
+ * Adds a group to the list of groups to consider for category value updates.
54491
+ *
54492
+ * @param {Element} groupShape
54493
+ * @param {ModdleElement} categoryValue
54494
+ * @param {boolean} isPresent
54495
+ */
54496
+ function addGroup(groupShape, categoryValue, isPresent) {
54497
+ if (!categoryValue) {
54498
+ return;
54499
+ }
54500
+
54501
+ var categoryGroup = categoryGroups.get(groupShape);
54502
+
54503
+ if (!categoryGroup) {
54504
+ categoryGroup = {};
54505
+ categoryGroups.set(groupShape, categoryGroup);
54506
+ }
54507
+
54508
+ if (isPresent && categoryGroup.present) {
54509
+ return;
54510
+ }
54511
+
54512
+ if (!isPresent && categoryGroup.past) {
54513
+ return;
54514
+ }
54515
+
54516
+ if (isPresent) {
54517
+ categoryGroup.present = {
54518
+ categoryValue: categoryValue,
54519
+ root: getRoot(groupShape)
54520
+ };
54521
+ } else {
54522
+ categoryGroup.past = {
54523
+ categoryValue: categoryValue
54524
+ };
54525
+ }
54526
+ }
54527
+
54528
+ /**
54529
+ * Adds a flow element to the list of flow elements to consider for category
54530
+ * value updates.
54531
+ *
54532
+ * @param {Element} flowElement
54533
+ */
54534
+ function addFlowElement(flowElement) {
54535
+ flowElementBusinessObjects.set(
54536
+ flowElement,
54537
+ getBusinessObject(flowElement)
54538
+ );
54539
+ }
54540
+
54541
+ /**
54542
+ * Adds all flow elements on the diagram to the list of flow elements to
54543
+ * consider; skips root elements (e.g. sub process planes) which share a
54544
+ * business object with their collapsed shape but carry no diagram position.
54545
+ */
54546
+ function addAllFlowElements() {
54547
+ elementRegistry.filter(function(element) {
54548
+ return is(element, 'bpmn:FlowElement') && !isLabel(element) && element.parent;
54549
+ }).forEach(addFlowElement);
54550
+ }
54551
+
54552
+ /**
54553
+ * Returns a group's category value, creating one on the fly for
54554
+ * legacy groups modeled without one. Retrieving the value in order to
54555
+ * reference it materializes it; the fresh value is recorded as a heal so
54556
+ * CategoryRootElementReferenceBehavior can maintain its root element.
54557
+ *
54558
+ * @param {Element} groupShape
54559
+ *
54560
+ * @return {ModdleElement}
54561
+ */
54562
+ function getCategoryValue(groupShape) {
54563
+ var groupBo = getBusinessObject(groupShape),
54564
+ categoryValue = groupBo.get('categoryValueRef');
54565
+
54566
+ if (!categoryValue) {
54567
+ categoryValue = getOrCreateCategoryValueForGroup(bpmnFactory, groupBo);
54568
+
54569
+ groupUpdates.push(createGroupUpdate(groupShape, categoryValue));
54570
+ }
54571
+
54572
+ return categoryValue;
54573
+ }
54574
+
54575
+ function getElementsByRoot(elements) {
54576
+ return elements.reduce(function(elementsByRoot, element) {
54577
+ var root = getRoot(element),
54578
+ elementsInRoot = elementsByRoot.get(root);
54579
+
54580
+ if (!elementsInRoot) {
54581
+ elementsInRoot = [];
54582
+ elementsByRoot.set(root, elementsInRoot);
54583
+ }
54584
+
54585
+ elementsInRoot.push(element);
54586
+
54587
+ return elementsByRoot;
54588
+ }, new Map());
54589
+ }
54590
+
54591
+ affectedFlowElements = Array.from(affectedFlowElements || []);
54592
+
54593
+ var affectedFlowElementsByRoot = getElementsByRoot(affectedFlowElements);
54594
+
54595
+ // when a group is moved, resized, added or removed, the category value
54596
+ // references of all flow elements must be rechecked
54597
+ if (affectedGroupEntries.length) {
54598
+ addAllFlowElements();
54599
+ }
54600
+
54601
+ // flow elements that were genuinely moved or created; unrelated groups
54602
+ // will not be touched
54603
+ affectedFlowElements.forEach(addFlowElement);
54604
+
54605
+ // add all present groups to the list of groups to consider for category
54606
+ // value updates, auto-healing legacy groups only when an affected flow
54607
+ // element moves into them
54608
+ elementRegistry.filter(function(element) {
54609
+ return is(element, 'bpmn:Group') && !isLabel(element) && element.parent;
54610
+ }).forEach(function(groupShape) {
54611
+ var categoryValue = getBusinessObject(groupShape).get('categoryValueRef');
54612
+
54613
+ if (!categoryValue) {
54614
+ var groupRoot = getRoot(groupShape),
54615
+ affectedFlowElementsInRoot = affectedFlowElementsByRoot.get(groupRoot) || [],
54616
+ enclosedAffectedFlowElements = getEnclosedElements(
54617
+ affectedFlowElementsInRoot,
54618
+ groupShape
54619
+ ),
54620
+ enclosesAffectedFlowElement = Object.keys(enclosedAffectedFlowElements).length > 0;
54621
+
54622
+ if (enclosesAffectedFlowElement) {
54623
+ categoryValue = getCategoryValue(groupShape);
54624
+ }
54625
+ }
54626
+
54627
+ addGroup(groupShape, categoryValue, true);
54628
+ });
54629
+
54630
+ affectedGroupEntries.forEach(function(groupEntry) {
54631
+ addGroup(groupEntry.groupShape, groupEntry.categoryValue, false);
54632
+ });
54633
+
54634
+ // a healed group receives a fresh category value; recheck all flow elements
54635
+ // so that everything it visually encloses is tagged consistently, not just
54636
+ // the flow element that triggered the healing
54637
+ if (groupUpdates.length) {
54638
+ addAllFlowElements();
54639
+ }
54640
+
54641
+ var flowElements = Array.from(flowElementBusinessObjects.keys());
54642
+
54643
+ var managedCategoryValues = Array.from(categoryGroups.values()).reduce(function(set, group) {
54644
+ if (group.present) {
54645
+ set.add(group.present.categoryValue);
54646
+ }
54647
+
54648
+ if (group.past) {
54649
+ set.add(group.past.categoryValue);
54650
+ }
54651
+
54652
+ return set;
54653
+ }, new Set());
54654
+
54655
+ var categoryValuesByFlowElement = new Map(),
54656
+ flowElementsByRoot = getElementsByRoot(flowElements);
54657
+
54658
+ // Containment is calculated once per group and diagram root. This avoids
54659
+ // allocating an enclosure result for every flow element / group pair.
54660
+ categoryGroups.forEach(function(categoryGroup, groupShape) {
54661
+ var presentGroup = categoryGroup.present;
54662
+
54663
+ if (!presentGroup) {
54664
+ return;
54665
+ }
54666
+
54667
+ var flowElementsInRoot = flowElementsByRoot.get(presentGroup.root) || [],
54668
+ enclosedFlowElements = getEnclosedElements(flowElementsInRoot, groupShape);
54669
+
54670
+ flowElementsInRoot.forEach(function(flowElement) {
54671
+ if (!enclosedFlowElements[flowElement.id]) {
54672
+ return;
54673
+ }
54674
+
54675
+ var categoryValues = categoryValuesByFlowElement.get(flowElement);
54676
+
54677
+ if (!categoryValues) {
54678
+ categoryValues = new Set();
54679
+ categoryValuesByFlowElement.set(flowElement, categoryValues);
54680
+ }
54681
+
54682
+ categoryValues.add(presentGroup.categoryValue);
54683
+ });
54684
+ });
54685
+
54686
+ // compute updates for all flow elements based on the groups they are inside
54687
+ var flowElementUpdates = flowElements.reduce(function(flowElementUpdates, flowElement) {
54688
+ var flowElementBo = flowElementBusinessObjects.get(flowElement),
54689
+ categoryValueRefs = flowElementBo.get(CATEGORY_VALUE_REFS_ATTR),
54690
+ categoryValueRefSet = new Set(categoryValueRefs),
54691
+ enclosingCategoryValues = categoryValuesByFlowElement.get(flowElement) || new Set(),
54692
+ categoryValuesToAdd = Array.from(enclosingCategoryValues).filter(function(categoryValue) {
54693
+ return !categoryValueRefSet.has(categoryValue);
54694
+ }),
54695
+ categoryValuesToRemove = categoryValueRefs.filter(function(categoryValue) {
54696
+ return managedCategoryValues.has(categoryValue) &&
54697
+ !enclosingCategoryValues.has(categoryValue);
54698
+ });
54699
+
54700
+ if (categoryValuesToAdd.length || categoryValuesToRemove.length) {
54701
+ flowElementUpdates.push({
54702
+ businessObject: flowElementBo,
54703
+ categoryValuesToAdd,
54704
+ categoryValuesToRemove
54705
+ });
54706
+ }
54707
+
54708
+ return flowElementUpdates;
54709
+ }, []);
54710
+
54711
+ return {
54712
+ flowElements: flowElementUpdates,
54713
+ groups: groupUpdates
54714
+ };
54715
+ };
54716
+
54717
+
54718
+ UpdateCategoryValueRefsHandler.prototype.execute = function(context) {
54719
+ var updates = context.updates;
54720
+
54721
+ if (!updates) {
54722
+ updates = context.updates = this._computeUpdates(
54723
+ context.affectedFlowElements,
54724
+ context.affectedGroupEntries
54725
+ );
54726
+ }
54727
+
54728
+ // set auto-healed category values first so that flow element updates can
54729
+ // reference them; root element linking is handled by
54730
+ // CategoryRootElementReferenceBehavior
54731
+ applyGroupUpdates(updates.groups);
54732
+
54733
+ applyFlowElementUpdates(updates.flowElements);
54734
+
54735
+ return [];
54736
+ };
54737
+
54738
+
54739
+ UpdateCategoryValueRefsHandler.prototype.revert = function(context) {
54740
+ var updates = context.updates;
54741
+
54742
+ revertFlowElementUpdates(updates.flowElements);
54743
+
54744
+ revertGroupUpdates(updates.groups);
54745
+
54746
+ return [];
54747
+ };
54748
+
54749
+
54750
+ function createGroupUpdate(groupShape, categoryValue) {
54751
+ return {
54752
+ groupShape: groupShape,
54753
+ categoryValue: categoryValue,
54754
+ category: categoryValue.$parent
54755
+ };
54756
+ }
54757
+
54758
+ function applyGroupUpdates(groupUpdates) {
54759
+ groupUpdates.forEach(function(groupUpdate) {
54760
+ getBusinessObject(groupUpdate.groupShape).categoryValueRef = groupUpdate.categoryValue;
54761
+ groupUpdate.categoryValue.$parent = groupUpdate.category;
54762
+ });
54763
+ }
54764
+
54765
+ function revertGroupUpdates(groupUpdates) {
54766
+ groupUpdates.forEach(function(groupUpdate) {
54767
+ getBusinessObject(groupUpdate.groupShape).categoryValueRef = null;
54768
+ });
54769
+ }
54770
+
54771
+ function applyFlowElementUpdates(flowElementUpdates) {
54772
+ flowElementUpdates.forEach(function(flowElementUpdate) {
54773
+ var businessObject = flowElementUpdate.businessObject,
54774
+ categoryValueRefs = businessObject.get(CATEGORY_VALUE_REFS_ATTR);
54775
+
54776
+ flowElementUpdate.categoryValuesToRemove.forEach(function(categoryValue) {
54777
+ remove(categoryValueRefs, categoryValue);
54778
+ });
54779
+
54780
+ flowElementUpdate.categoryValuesToAdd.forEach(function(categoryValue) {
54781
+ add(categoryValueRefs, categoryValue, true);
54782
+ });
54783
+ });
54784
+ }
54785
+
54786
+ function revertFlowElementUpdates(flowElementUpdates) {
54787
+ flowElementUpdates.forEach(function(flowElementUpdate) {
54788
+ var businessObject = flowElementUpdate.businessObject,
54789
+ categoryValueRefs = businessObject.get(CATEGORY_VALUE_REFS_ATTR);
54790
+
54791
+ flowElementUpdate.categoryValuesToAdd.forEach(function(categoryValue) {
54792
+ remove(categoryValueRefs, categoryValue);
54793
+ });
54794
+
54795
+ flowElementUpdate.categoryValuesToRemove.forEach(function(categoryValue) {
54796
+ add(categoryValueRefs, categoryValue, true);
54797
+ });
54798
+ });
54799
+ }
54800
+
54801
+ function getRoot(element) {
54802
+ while (element.parent) {
54803
+ element = element.parent;
54804
+ }
54805
+
54806
+ return element;
54807
+ }
54808
+
53804
54809
  /**
53805
54810
  * @typedef {import('diagram-js/lib/command/CommandHandler').default} CommandHandler
53806
54811
  *
@@ -54161,6 +55166,11 @@
54161
55166
  * @typedef { {
54162
55167
  * removeShape?: boolean;
54163
55168
  * } } UpdateLabelHints
55169
+ *
55170
+ * @typedef { {
55171
+ * categoryValue?: ModdleElement;
55172
+ * groupShape: Shape;
55173
+ * } } GroupEntry
54164
55174
  */
54165
55175
 
54166
55176
  /**
@@ -54211,6 +55221,7 @@
54211
55221
  handlers['lane.resize'] = ResizeLaneHandler;
54212
55222
  handlers['lane.split'] = SplitLaneHandler;
54213
55223
  handlers['lane.updateRefs'] = UpdateFlowNodeRefsHandler;
55224
+ handlers['group.updateRefs'] = UpdateCategoryValueRefsHandler;
54214
55225
  handlers['id.updateClaim'] = IdClaimHandler;
54215
55226
  handlers['element.setColor'] = SetColorHandler;
54216
55227
  handlers['element.updateLabel'] = UpdateLabelHandler;
@@ -54388,6 +55399,20 @@
54388
55399
  });
54389
55400
  };
54390
55401
 
55402
+ /**
55403
+ * Update the referenced category values of each flow element.
55404
+ *
55405
+ * @param {Element[]} affectedFlowElements The flow elements to update.
55406
+ * @param {GroupEntry[]} affectedGroupEntries The groups to update.
55407
+ */
55408
+ Modeling.prototype.updateCategoryValueRefs = function(affectedFlowElements, affectedGroupEntries) {
55409
+
55410
+ this._commandStack.execute('group.updateRefs', {
55411
+ affectedFlowElements: affectedFlowElements,
55412
+ affectedGroupEntries: affectedGroupEntries
55413
+ });
55414
+ };
55415
+
54391
55416
  /**
54392
55417
  * Claim an ID.
54393
55418
  *