camunda-bpmn-js 5.14.2 → 5.16.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.
@@ -1450,6 +1450,12 @@
1450
1450
  return el.querySelector(selector);
1451
1451
  }
1452
1452
 
1453
+ function all$2(selector, el) {
1454
+ el = el || document;
1455
+
1456
+ return el.querySelectorAll(selector);
1457
+ }
1458
+
1453
1459
  function remove$5(el) {
1454
1460
  el.parentNode && el.parentNode.removeChild(el);
1455
1461
  }
@@ -18870,6 +18876,17 @@
18870
18876
  return element;
18871
18877
  }
18872
18878
 
18879
+ /**
18880
+ * Returns true if the given element is an external label.
18881
+ *
18882
+ * @param {Element} element
18883
+ *
18884
+ * @return {boolean}
18885
+ */
18886
+ function isExternalLabel(element) {
18887
+ return isLabel(element) && isLabelExternal(element.labelTarget);
18888
+ }
18889
+
18873
18890
  var black = 'hsl(225, 10%, 15%)';
18874
18891
  var white = 'white';
18875
18892
 
@@ -19000,11 +19017,11 @@
19000
19017
  [ 'l', width - borderRadius * 2, 0 ],
19001
19018
  [ 'a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius ],
19002
19019
  [ 'l', 0, height - borderRadius * 2 ],
19003
- [ 'a', borderRadius, borderRadius, 0, 0, 1, -10, borderRadius ],
19020
+ [ 'a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius ],
19004
19021
  [ 'l', borderRadius * 2 - width, 0 ],
19005
- [ 'a', borderRadius, borderRadius, 0, 0, 1, -10, -10 ],
19022
+ [ 'a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius ],
19006
19023
  [ 'l', 0, borderRadius * 2 - height ],
19007
- [ 'a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -10 ],
19024
+ [ 'a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius ],
19008
19025
  [ 'z' ]
19009
19026
  ];
19010
19027
 
@@ -19102,7 +19119,8 @@
19102
19119
  var ELEMENT_LABEL_DISTANCE$1 = 10,
19103
19120
  INNER_OUTER_DIST = 3,
19104
19121
  PARTICIPANT_STROKE_WIDTH = 1.5,
19105
- TASK_BORDER_RADIUS = 10;
19122
+ TASK_BORDER_RADIUS = 10,
19123
+ EXTERNAL_LABEL_BORDER_RADIUS = 4;
19106
19124
 
19107
19125
  var DEFAULT_OPACITY = 0.95,
19108
19126
  FULL_OPACITY = 1,
@@ -21411,6 +21429,11 @@
21411
21429
  * @return {string} path
21412
21430
  */
21413
21431
  BpmnRenderer.prototype.getShapePath = function(shape) {
21432
+
21433
+ if (isLabel(shape)) {
21434
+ return getRoundRectPath(shape, EXTERNAL_LABEL_BORDER_RADIUS);
21435
+ }
21436
+
21414
21437
  if (is(shape, 'bpmn:Event')) {
21415
21438
  return getCirclePath(shape);
21416
21439
  }
@@ -25870,7 +25893,7 @@
25870
25893
  * @param {KeyboardEvent} event
25871
25894
  * @return {boolean}
25872
25895
  */
25873
- function isCmd(event) {
25896
+ function isCmd$1(event) {
25874
25897
 
25875
25898
  // ensure we don't react to AltGr
25876
25899
  // (mapped to CTRL + ALT)
@@ -25905,28 +25928,28 @@
25905
25928
  * @param {KeyboardEvent} event
25906
25929
  */
25907
25930
  function isCopy(event) {
25908
- return isCmd(event) && isKey(KEYS_COPY, event);
25931
+ return isCmd$1(event) && isKey(KEYS_COPY, event);
25909
25932
  }
25910
25933
 
25911
25934
  /**
25912
25935
  * @param {KeyboardEvent} event
25913
25936
  */
25914
25937
  function isPaste(event) {
25915
- return isCmd(event) && isKey(KEYS_PASTE, event);
25938
+ return isCmd$1(event) && isKey(KEYS_PASTE, event);
25916
25939
  }
25917
25940
 
25918
25941
  /**
25919
25942
  * @param {KeyboardEvent} event
25920
25943
  */
25921
25944
  function isUndo(event) {
25922
- return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
25945
+ return isCmd$1(event) && !isShift(event) && isKey(KEYS_UNDO, event);
25923
25946
  }
25924
25947
 
25925
25948
  /**
25926
25949
  * @param {KeyboardEvent} event
25927
25950
  */
25928
25951
  function isRedo(event) {
25929
- return isCmd(event) && (
25952
+ return isCmd$1(event) && (
25930
25953
  isKey(KEYS_REDO, event) || (
25931
25954
  isKey(KEYS_UNDO, event) && isShift(event)
25932
25955
  )
@@ -26130,7 +26153,7 @@
26130
26153
  };
26131
26154
 
26132
26155
  Keyboard.prototype.hasModifier = hasModifier;
26133
- Keyboard.prototype.isCmd = isCmd;
26156
+ Keyboard.prototype.isCmd = isCmd$1;
26134
26157
  Keyboard.prototype.isShift = isShift;
26135
26158
  Keyboard.prototype.isKey = isKey;
26136
26159
 
@@ -26248,7 +26271,7 @@
26248
26271
 
26249
26272
  // quirk: it has to be triggered by `=` as well to work on international keyboard layout
26250
26273
  // cf: https://github.com/bpmn-io/bpmn-js/issues/1362#issuecomment-722989754
26251
- if (isKey([ '+', 'Add', '=' ], event) && isCmd(event)) {
26274
+ if (isKey([ '+', 'Add', '=' ], event) && isCmd$1(event)) {
26252
26275
  editorActions.trigger('stepZoom', { value: 1 });
26253
26276
 
26254
26277
  return true;
@@ -26261,7 +26284,7 @@
26261
26284
 
26262
26285
  var event = context.keyEvent;
26263
26286
 
26264
- if (isKey([ '-', 'Subtract' ], event) && isCmd(event)) {
26287
+ if (isKey([ '-', 'Subtract' ], event) && isCmd$1(event)) {
26265
26288
  editorActions.trigger('stepZoom', { value: -1 });
26266
26289
 
26267
26290
  return true;
@@ -26274,7 +26297,7 @@
26274
26297
 
26275
26298
  var event = context.keyEvent;
26276
26299
 
26277
- if (isKey('0', event) && isCmd(event)) {
26300
+ if (isKey('0', event) && isCmd$1(event)) {
26278
26301
  editorActions.trigger('zoom', { value: 1 });
26279
26302
 
26280
26303
  return true;
@@ -35976,6 +35999,9 @@
35976
35999
  // create a DataObject every time a DataObjectReference is created
35977
36000
  var dataObject = bpmnFactory.create('bpmn:DataObject');
35978
36001
 
36002
+ // Copy the isCollection property if needed.
36003
+ dataObject.isCollection = shape.businessObject.dataObjectRef?.isCollection || false;
36004
+
35979
36005
  // set the reference to the DataObject
35980
36006
  shape.businessObject.dataObjectRef = dataObject;
35981
36007
  }
@@ -44985,7 +45011,8 @@
44985
45011
  'errorRef',
44986
45012
  'escalationRef',
44987
45013
  'messageRef',
44988
- 'signalRef'
45014
+ 'signalRef',
45015
+ 'dataObjectRef'
44989
45016
  ];
44990
45017
 
44991
45018
  /**
@@ -59581,7 +59608,7 @@
59581
59608
  ], LOWER_PRIORITY, function(event) {
59582
59609
  var originalEvent = event.originalEvent;
59583
59610
 
59584
- if (!self.active || (originalEvent && isCmd(originalEvent))) {
59611
+ if (!self.active || (originalEvent && isCmd$1(originalEvent))) {
59585
59612
  return;
59586
59613
  }
59587
59614
 
@@ -62119,6 +62146,487 @@
62119
62146
  labelEditingPreview: [ 'type', LabelEditingPreview ]
62120
62147
  };
62121
62148
 
62149
+ var LOW_PRIORITY$4 = 500;
62150
+
62151
+ var DEFAULT_PRIORITY$2 = 1000;
62152
+
62153
+ /**
62154
+ * @typedef {import('../../model/Types').Element} Element
62155
+ *
62156
+ * @typedef {import('./OutlineProvider').default} OutlineProvider
62157
+ * @typedef {import('../../core/EventBus').default} EventBus
62158
+ * @typedef {import('../../draw/Styles').default} Styles
62159
+ */
62160
+
62161
+ /**
62162
+ * @class
62163
+ *
62164
+ * A plugin that adds an outline to shapes and connections that may be activated and styled
62165
+ * via CSS classes.
62166
+ *
62167
+ * @param {EventBus} eventBus
62168
+ * @param {Styles} styles
62169
+ */
62170
+ function Outline$1(eventBus, styles) {
62171
+
62172
+ this._eventBus = eventBus;
62173
+
62174
+ this.offset = 5;
62175
+
62176
+ var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
62177
+
62178
+ var self = this;
62179
+
62180
+ /**
62181
+ * @param {SVGElement} gfx
62182
+ *
62183
+ * @return {SVGElement} outline
62184
+ */
62185
+ function createOutline(gfx) {
62186
+ var outline = create$1('rect');
62187
+
62188
+ attr$2(outline, assign$2({
62189
+ x: 0,
62190
+ y: 0,
62191
+ rx: 4,
62192
+ width: 100,
62193
+ height: 100
62194
+ }, OUTLINE_STYLE));
62195
+
62196
+ return outline;
62197
+ }
62198
+
62199
+ // A low priortity is necessary, because outlines of labels have to be updated
62200
+ // after the label bounds have been updated in the renderer.
62201
+ eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$4, function(event) {
62202
+ var element = event.element,
62203
+ gfx = event.gfx;
62204
+
62205
+ var outline = query$4('.djs-outline', gfx);
62206
+
62207
+ if (!outline) {
62208
+ outline = self.getOutline(element) || createOutline();
62209
+ append(gfx, outline);
62210
+ }
62211
+
62212
+ self.updateShapeOutline(outline, element);
62213
+ });
62214
+
62215
+ eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
62216
+ var element = event.element,
62217
+ gfx = event.gfx;
62218
+
62219
+ var outline = query$4('.djs-outline', gfx);
62220
+
62221
+ if (!outline) {
62222
+ outline = createOutline();
62223
+ append(gfx, outline);
62224
+ }
62225
+
62226
+ self.updateConnectionOutline(outline, element);
62227
+ });
62228
+ }
62229
+
62230
+
62231
+ /**
62232
+ * Updates the outline of a shape respecting the dimension of the
62233
+ * element and an outline offset.
62234
+ *
62235
+ * @param {SVGElement} outline
62236
+ * @param {Element} element
62237
+ */
62238
+ Outline$1.prototype.updateShapeOutline = function(outline, element) {
62239
+
62240
+ var updated = false;
62241
+ var providers = this._getProviders();
62242
+
62243
+ if (providers.length) {
62244
+ forEach$2(providers, function(provider) {
62245
+ updated = updated || provider.updateOutline(element, outline);
62246
+ });
62247
+ }
62248
+
62249
+ if (!updated) {
62250
+ attr$2(outline, {
62251
+ x: -this.offset,
62252
+ y: -this.offset,
62253
+ width: element.width + this.offset * 2,
62254
+ height: element.height + this.offset * 2
62255
+ });
62256
+ }
62257
+ };
62258
+
62259
+ /**
62260
+ * Updates the outline of a connection respecting the bounding box of
62261
+ * the connection and an outline offset.
62262
+ * Register an outline provider with the given priority.
62263
+ *
62264
+ * @param {SVGElement} outline
62265
+ * @param {Element} connection
62266
+ */
62267
+ Outline$1.prototype.updateConnectionOutline = function(outline, connection) {
62268
+ var bbox = getBBox(connection);
62269
+
62270
+ attr$2(outline, {
62271
+ x: bbox.x - this.offset,
62272
+ y: bbox.y - this.offset,
62273
+ width: bbox.width + this.offset * 2,
62274
+ height: bbox.height + this.offset * 2
62275
+ });
62276
+ };
62277
+
62278
+ /**
62279
+ * Register an outline provider with the given priority.
62280
+ *
62281
+ * @param {number} priority
62282
+ * @param {OutlineProvider} provider
62283
+ */
62284
+ Outline$1.prototype.registerProvider = function(priority, provider) {
62285
+ if (!provider) {
62286
+ provider = priority;
62287
+ priority = DEFAULT_PRIORITY$2;
62288
+ }
62289
+
62290
+ this._eventBus.on('outline.getProviders', priority, function(event) {
62291
+ event.providers.push(provider);
62292
+ });
62293
+ };
62294
+
62295
+ /**
62296
+ * Returns the registered outline providers.
62297
+ *
62298
+ * @returns {OutlineProvider[]}
62299
+ */
62300
+ Outline$1.prototype._getProviders = function() {
62301
+ var event = this._eventBus.createEvent({
62302
+ type: 'outline.getProviders',
62303
+ providers: []
62304
+ });
62305
+
62306
+ this._eventBus.fire(event);
62307
+
62308
+ return event.providers;
62309
+ };
62310
+
62311
+ /**
62312
+ * Returns the outline for an element.
62313
+ *
62314
+ * @param {Element} element
62315
+ */
62316
+ Outline$1.prototype.getOutline = function(element) {
62317
+ var outline;
62318
+ var providers = this._getProviders();
62319
+
62320
+ forEach$2(providers, function(provider) {
62321
+
62322
+ if (!isFunction(provider.getOutline)) {
62323
+ return;
62324
+ }
62325
+
62326
+ outline = outline || provider.getOutline(element);
62327
+ });
62328
+
62329
+ return outline;
62330
+ };
62331
+
62332
+ Outline$1.$inject = [ 'eventBus', 'styles', 'elementRegistry' ];
62333
+
62334
+ var SELECTION_OUTLINE_PADDING = 6;
62335
+
62336
+ /**
62337
+ * @typedef {import('../../model/Types').Element} Element
62338
+ *
62339
+ * @typedef {import('../../core/EventBus').default} EventBus
62340
+ * @typedef {import('../selection/Selection').default} Selection
62341
+ * @typedef {import('../../core/Canvas').default} Canvas
62342
+ */
62343
+
62344
+ /**
62345
+ * @class
62346
+ *
62347
+ * A plugin that adds an outline to shapes and connections that may be activated and styled
62348
+ * via CSS classes.
62349
+ *
62350
+ * @param {EventBus} eventBus
62351
+ * @param {Canvas} canvas
62352
+ * @param {Selection} selection
62353
+ */
62354
+ function MultiSelectionOutline(eventBus, canvas, selection) {
62355
+ this._canvas = canvas;
62356
+
62357
+ var self = this;
62358
+
62359
+ eventBus.on('element.changed', function(event) {
62360
+ if (selection.isSelected(event.element)) {
62361
+ self._updateMultiSelectionOutline(selection.get());
62362
+ }
62363
+ });
62364
+
62365
+ eventBus.on('selection.changed', function(event) {
62366
+ var newSelection = event.newSelection;
62367
+
62368
+ self._updateMultiSelectionOutline(newSelection);
62369
+ });
62370
+ }
62371
+
62372
+
62373
+
62374
+ MultiSelectionOutline.prototype._updateMultiSelectionOutline = function(selection) {
62375
+ var layer = this._canvas.getLayer('selectionOutline');
62376
+
62377
+ clear$1(layer);
62378
+
62379
+ var enabled = selection.length > 1;
62380
+
62381
+ var container = this._canvas.getContainer();
62382
+
62383
+ classes$2(container)[enabled ? 'add' : 'remove']('djs-multi-select');
62384
+
62385
+ if (!enabled) {
62386
+ return;
62387
+ }
62388
+
62389
+ var bBox = addSelectionOutlinePadding(getBBox(selection));
62390
+
62391
+ var rect = create$1('rect');
62392
+
62393
+ attr$2(rect, assign$2({
62394
+ rx: 3
62395
+ }, bBox));
62396
+
62397
+ classes$2(rect).add('djs-selection-outline');
62398
+
62399
+ append(layer, rect);
62400
+ };
62401
+
62402
+
62403
+ MultiSelectionOutline.$inject = [ 'eventBus', 'canvas', 'selection' ];
62404
+
62405
+ // helpers //////////
62406
+
62407
+ function addSelectionOutlinePadding(bBox) {
62408
+ return {
62409
+ x: bBox.x - SELECTION_OUTLINE_PADDING,
62410
+ y: bBox.y - SELECTION_OUTLINE_PADDING,
62411
+ width: bBox.width + SELECTION_OUTLINE_PADDING * 2,
62412
+ height: bBox.height + SELECTION_OUTLINE_PADDING * 2
62413
+ };
62414
+ }
62415
+
62416
+ /**
62417
+ * @type { import('didi').ModuleDeclaration }
62418
+ */
62419
+ var Outline = {
62420
+ __depends__: [
62421
+ SelectionModule
62422
+ ],
62423
+ __init__: [ 'outline', 'multiSelectionOutline' ],
62424
+ outline: [ 'type', Outline$1 ],
62425
+ multiSelectionOutline: [ 'type', MultiSelectionOutline ]
62426
+ };
62427
+
62428
+ /**
62429
+ * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
62430
+ * @typedef {import('diagram-js/lib/core/Canvas').default} Canvas
62431
+ * @typedef {import('diagram-js/lib/core/GraphicsFactory').default} GraphicsFactory
62432
+ * @typedef {import('../outline/OutlineProvider').default} Outline
62433
+ * @typedef {import('diagram-js/lib/features/selection').default} Selection
62434
+ *
62435
+ * @typedef {import('diagram-js/lib/model/Types').Element} Element
62436
+ */
62437
+
62438
+ const ALLOWED_ELEMENTS = [ 'bpmn:Event', 'bpmn:SequenceFlow', 'bpmn:Gateway' ];
62439
+
62440
+ const LINE_STYLE = {
62441
+ class: 'bjs-label-link',
62442
+ stroke: 'var(--element-selected-outline-secondary-stroke-color)',
62443
+ strokeDasharray: '5, 5',
62444
+ };
62445
+
62446
+ const DISTANCE_THRESHOLD = 15;
62447
+ const PATH_OFFSET = 2;
62448
+
62449
+ /**
62450
+ * Render a line between an external label and its target element,
62451
+ * when either is selected.
62452
+ *
62453
+ * @param {EventBus} eventBus
62454
+ * @param {Canvas} canvas
62455
+ * @param {GraphicsFactory} graphicsFactory
62456
+ * @param {Outline} outline
62457
+ */
62458
+ function LabelLink$1(eventBus, canvas, graphicsFactory, outline, selection) {
62459
+
62460
+ const layer = canvas.getLayer('overlays');
62461
+
62462
+ eventBus.on([ 'selection.changed', 'shape.changed' ], function() {
62463
+ cleanUp();
62464
+ });
62465
+
62466
+ eventBus.on('selection.changed', function({ newSelection }) {
62467
+
62468
+ const allowedElements = newSelection.filter(element => isAny(element, ALLOWED_ELEMENTS));
62469
+
62470
+ if (allowedElements.length === 1) {
62471
+ const element = allowedElements[0];
62472
+ if (isLabel(element)) {
62473
+ createLink(element, element.labelTarget, newSelection);
62474
+ } else if (element.labels?.length) {
62475
+ createLink(element.labels[0], element, newSelection);
62476
+ }
62477
+ }
62478
+
62479
+ // Only allowed when both label and its target are selected
62480
+ if (allowedElements.length === 2) {
62481
+ const label = allowedElements.find(isLabel);
62482
+ const target = allowedElements.find(el => el.labels?.includes(label));
62483
+ if (label && target) {
62484
+ createLink(label, target, newSelection);
62485
+ }
62486
+ }
62487
+ });
62488
+
62489
+ eventBus.on('shape.changed', function({ element }) {
62490
+
62491
+ if (!isAny(element, ALLOWED_ELEMENTS) || !isElementSelected(element)) {
62492
+ return;
62493
+ }
62494
+
62495
+ if (isLabel(element)) {
62496
+ createLink(element, element.labelTarget, selection.get());
62497
+ } else if (element.labels?.length) {
62498
+ createLink(element.labels[0], element, selection.get());
62499
+ }
62500
+ });
62501
+
62502
+ /**
62503
+ * Render a line between an external label and its target.
62504
+ *
62505
+ * @param {Element} label
62506
+ * @param {Element} target
62507
+ * @param {Element[]} selection
62508
+ */
62509
+ function createLink(label, target, selection = []) {
62510
+
62511
+ // Create an auxiliary line between label and target mid points
62512
+ const line = createLine(
62513
+ [ getMid(target), getMid(label) ],
62514
+ LINE_STYLE
62515
+ );
62516
+ const linePath = line.getAttribute('d');
62517
+
62518
+ // Calculate the intersection point between line and label
62519
+ const labelSelected = selection.includes(label);
62520
+ const labelPath = labelSelected ? getElementOutlinePath(label) : getElementPath(label);
62521
+ const labelInter = getElementLineIntersection(labelPath, linePath);
62522
+
62523
+ // Label on top of the target
62524
+ if (!labelInter) {
62525
+ return;
62526
+ }
62527
+
62528
+ // Calculate the intersection point between line and label
62529
+ // If the target is a sequence flow, there is no intersection,
62530
+ // so we link to the middle of it.
62531
+ const targetSelected = selection.includes(target);
62532
+ const targetPath = targetSelected ? getElementOutlinePath(target) : getElementPath(target);
62533
+ const targetInter = getElementLineIntersection(targetPath, linePath) || getMid(target);
62534
+
62535
+ // Do not draw a link if the points are too close
62536
+ const distance = getDistancePointPoint(targetInter, labelInter);
62537
+ if (distance < DISTANCE_THRESHOLD) {
62538
+ return;
62539
+ }
62540
+
62541
+ // Connect the actual closest points
62542
+ updateLine(line, [ targetInter, labelInter ]);
62543
+ append(layer, line);
62544
+ }
62545
+
62546
+ /**
62547
+ * Remove all existing label links.
62548
+ */
62549
+ function cleanUp() {
62550
+ all$2(`.${LINE_STYLE.class}`, layer).forEach(remove$4);
62551
+ }
62552
+
62553
+ /**
62554
+ * Get element's slightly expanded outline path.
62555
+ *
62556
+ * @param {Element} element
62557
+ * @returns {string} svg path
62558
+ */
62559
+ function getElementOutlinePath(element) {
62560
+ const outlineShape = outline.getOutline(element);
62561
+ const outlineOffset = outline.offset;
62562
+
62563
+ if (!outlineShape) {
62564
+ return getElementPath(element);
62565
+ }
62566
+
62567
+ if (outlineShape.x) {
62568
+ const shape = {
62569
+ x: element.x + parseSvgNumAttr(outlineShape, 'x') - PATH_OFFSET,
62570
+ y: element.y + parseSvgNumAttr(outlineShape, 'y') - PATH_OFFSET,
62571
+ width: parseSvgNumAttr(outlineShape, 'width') + PATH_OFFSET * 2,
62572
+ height: parseSvgNumAttr(outlineShape, 'height') + PATH_OFFSET * 2
62573
+ };
62574
+
62575
+ return getRoundRectPath(shape, parseSvgNumAttr(outlineShape, 'rx'));
62576
+ }
62577
+
62578
+ if (outlineShape.cx) {
62579
+ const shape = {
62580
+ x: element.x - outlineOffset,
62581
+ y: element.y - outlineOffset,
62582
+ width: parseSvgNumAttr(outlineShape, 'r') * 2,
62583
+ height: parseSvgNumAttr(outlineShape, 'r') * 2,
62584
+ };
62585
+
62586
+ return getCirclePath(shape);
62587
+ }
62588
+ }
62589
+
62590
+ function getElementPath(element) {
62591
+ return graphicsFactory.getShapePath(element);
62592
+ }
62593
+
62594
+ function isElementSelected(element) {
62595
+ return selection.get().includes(element);
62596
+ }
62597
+ }
62598
+
62599
+ LabelLink$1.$inject = [
62600
+ 'eventBus',
62601
+ 'canvas',
62602
+ 'graphicsFactory',
62603
+ 'outline',
62604
+ 'selection'
62605
+ ];
62606
+
62607
+ /**
62608
+ * Get numeric attribute from SVG element
62609
+ * or 0 if not present.
62610
+ *
62611
+ * @param {SVGElement} node
62612
+ * @param {string} attr
62613
+ * @returns {number}
62614
+ */
62615
+ function parseSvgNumAttr(node, attr) {
62616
+ return parseFloat(attr$2(node, attr) || 0);
62617
+ }
62618
+
62619
+ var LabelLink = {
62620
+ __depends__: [
62621
+ SelectionModule,
62622
+ Outline
62623
+ ],
62624
+ __init__: [
62625
+ 'labelLink'
62626
+ ],
62627
+ labelLink: [ 'type', LabelLink$1 ]
62628
+ };
62629
+
62122
62630
  /**
62123
62631
  * @typedef {import('../../core/Canvas').default} Canvas
62124
62632
  * @typedef {import('../../core/EventBus').default} EventBus
@@ -62566,285 +63074,6 @@
62566
63074
  modelingFeedback: [ 'type', ModelingFeedback ]
62567
63075
  };
62568
63076
 
62569
- var LOW_PRIORITY$4 = 500;
62570
-
62571
- var DEFAULT_PRIORITY$2 = 1000;
62572
-
62573
- /**
62574
- * @typedef {import('../../model/Types').Element} Element
62575
- *
62576
- * @typedef {import('./OutlineProvider').default} OutlineProvider
62577
- * @typedef {import('../../core/EventBus').default} EventBus
62578
- * @typedef {import('../../draw/Styles').default} Styles
62579
- */
62580
-
62581
- /**
62582
- * @class
62583
- *
62584
- * A plugin that adds an outline to shapes and connections that may be activated and styled
62585
- * via CSS classes.
62586
- *
62587
- * @param {EventBus} eventBus
62588
- * @param {Styles} styles
62589
- */
62590
- function Outline(eventBus, styles) {
62591
-
62592
- this._eventBus = eventBus;
62593
-
62594
- this.offset = 5;
62595
-
62596
- var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
62597
-
62598
- var self = this;
62599
-
62600
- /**
62601
- * @param {SVGElement} gfx
62602
- *
62603
- * @return {SVGElement} outline
62604
- */
62605
- function createOutline(gfx) {
62606
- var outline = create$1('rect');
62607
-
62608
- attr$2(outline, assign$2({
62609
- x: 0,
62610
- y: 0,
62611
- rx: 4,
62612
- width: 100,
62613
- height: 100
62614
- }, OUTLINE_STYLE));
62615
-
62616
- return outline;
62617
- }
62618
-
62619
- // A low priortity is necessary, because outlines of labels have to be updated
62620
- // after the label bounds have been updated in the renderer.
62621
- eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$4, function(event) {
62622
- var element = event.element,
62623
- gfx = event.gfx;
62624
-
62625
- var outline = query$4('.djs-outline', gfx);
62626
-
62627
- if (!outline) {
62628
- outline = self.getOutline(element) || createOutline();
62629
- append(gfx, outline);
62630
- }
62631
-
62632
- self.updateShapeOutline(outline, element);
62633
- });
62634
-
62635
- eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
62636
- var element = event.element,
62637
- gfx = event.gfx;
62638
-
62639
- var outline = query$4('.djs-outline', gfx);
62640
-
62641
- if (!outline) {
62642
- outline = createOutline();
62643
- append(gfx, outline);
62644
- }
62645
-
62646
- self.updateConnectionOutline(outline, element);
62647
- });
62648
- }
62649
-
62650
-
62651
- /**
62652
- * Updates the outline of a shape respecting the dimension of the
62653
- * element and an outline offset.
62654
- *
62655
- * @param {SVGElement} outline
62656
- * @param {Element} element
62657
- */
62658
- Outline.prototype.updateShapeOutline = function(outline, element) {
62659
-
62660
- var updated = false;
62661
- var providers = this._getProviders();
62662
-
62663
- if (providers.length) {
62664
- forEach$2(providers, function(provider) {
62665
- updated = updated || provider.updateOutline(element, outline);
62666
- });
62667
- }
62668
-
62669
- if (!updated) {
62670
- attr$2(outline, {
62671
- x: -this.offset,
62672
- y: -this.offset,
62673
- width: element.width + this.offset * 2,
62674
- height: element.height + this.offset * 2
62675
- });
62676
- }
62677
- };
62678
-
62679
- /**
62680
- * Updates the outline of a connection respecting the bounding box of
62681
- * the connection and an outline offset.
62682
- * Register an outline provider with the given priority.
62683
- *
62684
- * @param {SVGElement} outline
62685
- * @param {Element} connection
62686
- */
62687
- Outline.prototype.updateConnectionOutline = function(outline, connection) {
62688
- var bbox = getBBox(connection);
62689
-
62690
- attr$2(outline, {
62691
- x: bbox.x - this.offset,
62692
- y: bbox.y - this.offset,
62693
- width: bbox.width + this.offset * 2,
62694
- height: bbox.height + this.offset * 2
62695
- });
62696
- };
62697
-
62698
- /**
62699
- * Register an outline provider with the given priority.
62700
- *
62701
- * @param {number} priority
62702
- * @param {OutlineProvider} provider
62703
- */
62704
- Outline.prototype.registerProvider = function(priority, provider) {
62705
- if (!provider) {
62706
- provider = priority;
62707
- priority = DEFAULT_PRIORITY$2;
62708
- }
62709
-
62710
- this._eventBus.on('outline.getProviders', priority, function(event) {
62711
- event.providers.push(provider);
62712
- });
62713
- };
62714
-
62715
- /**
62716
- * Returns the registered outline providers.
62717
- *
62718
- * @returns {OutlineProvider[]}
62719
- */
62720
- Outline.prototype._getProviders = function() {
62721
- var event = this._eventBus.createEvent({
62722
- type: 'outline.getProviders',
62723
- providers: []
62724
- });
62725
-
62726
- this._eventBus.fire(event);
62727
-
62728
- return event.providers;
62729
- };
62730
-
62731
- /**
62732
- * Returns the outline for an element.
62733
- *
62734
- * @param {Element} element
62735
- */
62736
- Outline.prototype.getOutline = function(element) {
62737
- var outline;
62738
- var providers = this._getProviders();
62739
-
62740
- forEach$2(providers, function(provider) {
62741
-
62742
- if (!isFunction(provider.getOutline)) {
62743
- return;
62744
- }
62745
-
62746
- outline = outline || provider.getOutline(element);
62747
- });
62748
-
62749
- return outline;
62750
- };
62751
-
62752
- Outline.$inject = [ 'eventBus', 'styles', 'elementRegistry' ];
62753
-
62754
- var SELECTION_OUTLINE_PADDING = 6;
62755
-
62756
- /**
62757
- * @typedef {import('../../model/Types').Element} Element
62758
- *
62759
- * @typedef {import('../../core/EventBus').default} EventBus
62760
- * @typedef {import('../selection/Selection').default} Selection
62761
- * @typedef {import('../../core/Canvas').default} Canvas
62762
- */
62763
-
62764
- /**
62765
- * @class
62766
- *
62767
- * A plugin that adds an outline to shapes and connections that may be activated and styled
62768
- * via CSS classes.
62769
- *
62770
- * @param {EventBus} eventBus
62771
- * @param {Canvas} canvas
62772
- * @param {Selection} selection
62773
- */
62774
- function MultiSelectionOutline(eventBus, canvas, selection) {
62775
- this._canvas = canvas;
62776
-
62777
- var self = this;
62778
-
62779
- eventBus.on('element.changed', function(event) {
62780
- if (selection.isSelected(event.element)) {
62781
- self._updateMultiSelectionOutline(selection.get());
62782
- }
62783
- });
62784
-
62785
- eventBus.on('selection.changed', function(event) {
62786
- var newSelection = event.newSelection;
62787
-
62788
- self._updateMultiSelectionOutline(newSelection);
62789
- });
62790
- }
62791
-
62792
-
62793
-
62794
- MultiSelectionOutline.prototype._updateMultiSelectionOutline = function(selection) {
62795
- var layer = this._canvas.getLayer('selectionOutline');
62796
-
62797
- clear$1(layer);
62798
-
62799
- var enabled = selection.length > 1;
62800
-
62801
- var container = this._canvas.getContainer();
62802
-
62803
- classes$2(container)[enabled ? 'add' : 'remove']('djs-multi-select');
62804
-
62805
- if (!enabled) {
62806
- return;
62807
- }
62808
-
62809
- var bBox = addSelectionOutlinePadding(getBBox(selection));
62810
-
62811
- var rect = create$1('rect');
62812
-
62813
- attr$2(rect, assign$2({
62814
- rx: 3
62815
- }, bBox));
62816
-
62817
- classes$2(rect).add('djs-selection-outline');
62818
-
62819
- append(layer, rect);
62820
- };
62821
-
62822
-
62823
- MultiSelectionOutline.$inject = [ 'eventBus', 'canvas', 'selection' ];
62824
-
62825
- // helpers //////////
62826
-
62827
- function addSelectionOutlinePadding(bBox) {
62828
- return {
62829
- x: bBox.x - SELECTION_OUTLINE_PADDING,
62830
- y: bBox.y - SELECTION_OUTLINE_PADDING,
62831
- width: bBox.width + SELECTION_OUTLINE_PADDING * 2,
62832
- height: bBox.height + SELECTION_OUTLINE_PADDING * 2
62833
- };
62834
- }
62835
-
62836
- /**
62837
- * @type { import('didi').ModuleDeclaration }
62838
- */
62839
- var Ouline = {
62840
- __depends__: [
62841
- SelectionModule
62842
- ],
62843
- __init__: [ 'outline', 'multiSelectionOutline' ],
62844
- outline: [ 'type', Outline ],
62845
- multiSelectionOutline: [ 'type', MultiSelectionOutline ]
62846
- };
62847
-
62848
63077
  /**
62849
63078
  * @typedef {import('../../core/Types').ElementLike} Element
62850
63079
  * @typedef {import('../../core/Types').ShapeLike} Shape
@@ -63347,7 +63576,7 @@
63347
63576
  __depends__: [
63348
63577
  InteractionEventsModule$1,
63349
63578
  SelectionModule,
63350
- Ouline,
63579
+ Outline,
63351
63580
  RulesModule$1,
63352
63581
  DraggingModule,
63353
63582
  PreviewSupportModule
@@ -64923,7 +65152,7 @@
64923
65152
  target = context.target;
64924
65153
 
64925
65154
  // do NOT snap on CMD
64926
- if (event.originalEvent && isCmd(event.originalEvent)) {
65155
+ if (event.originalEvent && isCmd$1(event.originalEvent)) {
64927
65156
  return;
64928
65157
  }
64929
65158
 
@@ -65362,7 +65591,7 @@
65362
65591
  snapContext = context.snapContext,
65363
65592
  target = context.target;
65364
65593
 
65365
- if (event.originalEvent && isCmd(event.originalEvent)) {
65594
+ if (event.originalEvent && isCmd$1(event.originalEvent)) {
65366
65595
  return;
65367
65596
  }
65368
65597
 
@@ -65811,7 +66040,7 @@
65811
66040
  direction = context.direction,
65812
66041
  snapContext = context.snapContext;
65813
66042
 
65814
- if (event.originalEvent && isCmd(event.originalEvent)) {
66043
+ if (event.originalEvent && isCmd$1(event.originalEvent)) {
65815
66044
  return;
65816
66045
  }
65817
66046
 
@@ -66835,6 +67064,20 @@
66835
67064
 
66836
67065
  var outline;
66837
67066
 
67067
+ if (isExternalLabel(element)) {
67068
+ outline = create$1('rect');
67069
+
67070
+ attr$2(outline, assign$2({
67071
+ x: -5,
67072
+ y: -5,
67073
+ rx: 4,
67074
+ width: element.width + DEFAULT_OFFSET * 2,
67075
+ height: element.height + DEFAULT_OFFSET * 2
67076
+ }, OUTLINE_STYLE));
67077
+
67078
+ return outline;
67079
+ }
67080
+
66838
67081
  if (isLabel(element)) {
66839
67082
  return;
66840
67083
  }
@@ -66962,7 +67205,7 @@
66962
67205
 
66963
67206
  var OutlineModule = {
66964
67207
  __depends__: [
66965
- Ouline
67208
+ Outline
66966
67209
  ],
66967
67210
  __init__: [ 'outlineProvider' ],
66968
67211
  outlineProvider: [ 'type', OutlineProvider ]
@@ -67113,6 +67356,7 @@
67113
67356
  KeyboardModule,
67114
67357
  KeyboardMoveSelectionModule,
67115
67358
  LabelEditingModule,
67359
+ LabelLink,
67116
67360
  ModelingModule,
67117
67361
  ModelingFeedbackModule,
67118
67362
  MoveModule,
@@ -69288,6 +69532,7 @@
69288
69532
  this.deserialize = config.deserialize || (() => {
69289
69533
  throw new Error("This node type doesn't define a deserialize function");
69290
69534
  });
69535
+ this.combine = config.combine || null;
69291
69536
  }
69292
69537
  /**
69293
69538
  This is meant to be used with
@@ -69552,7 +69797,10 @@
69552
69797
  if (add) {
69553
69798
  if (!newProps)
69554
69799
  newProps = Object.assign({}, type.props);
69555
- newProps[add[0].id] = add[1];
69800
+ let value = add[1], prop = add[0];
69801
+ if (prop.combine && prop.id in newProps)
69802
+ value = prop.combine(newProps[prop.id], value);
69803
+ newProps[prop.id] = value;
69556
69804
  }
69557
69805
  }
69558
69806
  newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type);
@@ -70025,6 +70273,7 @@
70025
70273
  get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* Side.DontCare */); }
70026
70274
  childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* Side.After */); }
70027
70275
  childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Side.Before */); }
70276
+ prop(prop) { return this._tree.prop(prop); }
70028
70277
  enter(pos, side, mode = 0) {
70029
70278
  let mounted;
70030
70279
  if (!(mode & IterMode.IgnoreOverlays) && (mounted = MountedTree.get(this._tree)) && mounted.overlay) {
@@ -70118,6 +70367,7 @@
70118
70367
  get lastChild() { return this.child(-1, 0, 4 /* Side.DontCare */); }
70119
70368
  childAfter(pos) { return this.child(1, pos, 2 /* Side.After */); }
70120
70369
  childBefore(pos) { return this.child(-1, pos, -2 /* Side.Before */); }
70370
+ prop(prop) { return this.type.prop(prop); }
70121
70371
  enter(pos, side, mode = 0) {
70122
70372
  if (mode & IterMode.ExcludeBuffers)
70123
70373
  return null;
@@ -70535,7 +70785,7 @@
70535
70785
  function takeNode(parentStart, minPos, children, positions, inRepeat, depth) {
70536
70786
  let { id, start, end, size } = cursor;
70537
70787
  let lookAheadAtStart = lookAhead, contextAtStart = contextHash;
70538
- while (size < 0) {
70788
+ if (size < 0) {
70539
70789
  cursor.next();
70540
70790
  if (size == -1 /* SpecialRecord.Reuse */) {
70541
70791
  let node = reused[id];
@@ -70699,7 +70949,7 @@
70699
70949
  fork.next();
70700
70950
  while (fork.pos > startPos) {
70701
70951
  if (fork.size < 0) {
70702
- if (fork.size == -3 /* SpecialRecord.ContextChange */)
70952
+ if (fork.size == -3 /* SpecialRecord.ContextChange */ || fork.size == -4 /* SpecialRecord.LookAhead */)
70703
70953
  localSkipped += 4;
70704
70954
  else
70705
70955
  break scan;
@@ -71088,8 +71338,15 @@
71088
71338
  }
71089
71339
  else if (!cursor.type.isAnonymous && (nest = this.nest(cursor, this.input)) &&
71090
71340
  (cursor.from < cursor.to || !nest.overlay)) {
71091
- if (!cursor.tree)
71341
+ if (!cursor.tree) {
71092
71342
  materialize(cursor);
71343
+ // materialize create one more level of nesting
71344
+ // we need to add depth to active overlay for going backwards
71345
+ if (overlay)
71346
+ overlay.depth++;
71347
+ if (covered)
71348
+ covered.depth++;
71349
+ }
71093
71350
  let oldMounts = fragmentCursor.findMounts(cursor.from, nest.parser);
71094
71351
  if (typeof nest.overlay == "function") {
71095
71352
  overlay = new ActiveOverlay(nest.parser, nest.overlay, oldMounts, this.inner.length, cursor.from, cursor.tree, overlay);
@@ -71501,9 +71758,7 @@
71501
71758
  var _a;
71502
71759
  let depth = action >> 19 /* Action.ReduceDepthShift */, type = action & 65535 /* Action.ValueMask */;
71503
71760
  let { parser } = this.p;
71504
- let lookaheadRecord = this.reducePos < this.pos - 25 /* Lookahead.Margin */;
71505
- if (lookaheadRecord)
71506
- this.setLookAhead(this.pos);
71761
+ let lookaheadRecord = this.reducePos < this.pos - 25 /* Lookahead.Margin */ && this.setLookAhead(this.pos);
71507
71762
  let dPrec = parser.dynamicPrecedence(type);
71508
71763
  if (dPrec)
71509
71764
  this.score += dPrec;
@@ -71581,7 +71836,7 @@
71581
71836
  }
71582
71837
  else { // There may be skipped nodes that have to be moved forward
71583
71838
  let index = this.buffer.length;
71584
- if (index > 0 && this.buffer[index - 4] != 0 /* Term.Err */) {
71839
+ if (index > 0 && (this.buffer[index - 4] != 0 /* Term.Err */ || this.buffer[index - 1] < 0)) {
71585
71840
  let mustMove = false;
71586
71841
  for (let scan = index; scan > 0 && this.buffer[scan - 2] > end; scan -= 4) {
71587
71842
  if (this.buffer[scan - 1] >= 0) {
@@ -71894,10 +72149,11 @@
71894
72149
  @internal
71895
72150
  */
71896
72151
  setLookAhead(lookAhead) {
71897
- if (lookAhead > this.lookAhead) {
71898
- this.emitLookAhead();
71899
- this.lookAhead = lookAhead;
71900
- }
72152
+ if (lookAhead <= this.lookAhead)
72153
+ return false;
72154
+ this.emitLookAhead();
72155
+ this.lookAhead = lookAhead;
72156
+ return true;
71901
72157
  }
71902
72158
  /**
71903
72159
  @internal
@@ -72726,8 +72982,10 @@
72726
72982
  }
72727
72983
  }
72728
72984
  }
72729
- if (newStacks.length > 12 /* Rec.MaxStackCount */)
72985
+ if (newStacks.length > 12 /* Rec.MaxStackCount */) {
72986
+ newStacks.sort((a, b) => b.score - a.score);
72730
72987
  newStacks.splice(12 /* Rec.MaxStackCount */, newStacks.length - 12 /* Rec.MaxStackCount */);
72988
+ }
72731
72989
  }
72732
72990
  this.minStackPos = newStacks[0].pos;
72733
72991
  for (let i = 1; i < newStacks.length; i++)
@@ -72828,7 +73086,7 @@
72828
73086
  continue;
72829
73087
  }
72830
73088
  let force = stack.split(), forceBase = base;
72831
- for (let j = 0; force.forceReduce() && j < 10 /* Rec.ForceReduceLimit */; j++) {
73089
+ for (let j = 0; j < 10 /* Rec.ForceReduceLimit */ && force.forceReduce(); j++) {
72832
73090
  if (verbose)
72833
73091
  console.log(forceBase + this.stackID(force) + " (via force-reduce)");
72834
73092
  let done = this.advanceFully(force, newStacks);
@@ -73389,7 +73647,7 @@
73389
73647
  For example:
73390
73648
 
73391
73649
  ```javascript
73392
- parser.withProps(
73650
+ parser.configure({props: [
73393
73651
  styleTags({
73394
73652
  // Style Number and BigNumber nodes
73395
73653
  "Number BigNumber": tags.number,
@@ -73404,7 +73662,7 @@
73404
73662
  // Style the node named "/" as punctuation
73405
73663
  '"/"': tags.punctuation
73406
73664
  })
73407
- )
73665
+ ]})
73408
73666
  ```
73409
73667
  */
73410
73668
  function styleTags(spec) {
@@ -73446,7 +73704,30 @@
73446
73704
  }
73447
73705
  return ruleNodeProp.add(byName);
73448
73706
  }
73449
- const ruleNodeProp = new NodeProp();
73707
+ const ruleNodeProp = new NodeProp({
73708
+ combine(a, b) {
73709
+ let cur, root, take;
73710
+ while (a || b) {
73711
+ if (!a || b && a.depth >= b.depth) {
73712
+ take = b;
73713
+ b = b.next;
73714
+ }
73715
+ else {
73716
+ take = a;
73717
+ a = a.next;
73718
+ }
73719
+ if (cur && cur.mode == take.mode && !take.context && !cur.context)
73720
+ continue;
73721
+ let copy = new Rule(take.tags, take.mode, take.context);
73722
+ if (cur)
73723
+ cur.next = copy;
73724
+ else
73725
+ root = copy;
73726
+ cur = copy;
73727
+ }
73728
+ return root;
73729
+ }
73730
+ });
73450
73731
  class Rule {
73451
73732
  constructor(tags, mode, context, next) {
73452
73733
  this.tags = tags;
@@ -103304,22 +103585,30 @@
103304
103585
  var OpenPopupIcon = function OpenPopupIcon(props) {
103305
103586
  return u("svg", {
103306
103587
  ...props,
103307
- children: [u("path", {
103308
- fill: "currentColor",
103309
- d: "M28 4H10a2.006 2.006 0 0 0-2 2v14a2.006 2.006 0 0 0 2 2h18a2.006 2.006 0 0 0 2-2V6a2.006 2.006 0 0 0-2-2Zm0 16H10V6h18Z"
103310
- }), u("path", {
103311
- fill: "currentColor",
103312
- d: "M18 26H4V16h2v-2H4a2.006 2.006 0 0 0-2 2v10a2.006 2.006 0 0 0 2 2h14a2.006 2.006 0 0 0 2-2v-2h-2Z"
103313
- })]
103588
+ children: u("path", {
103589
+ d: "M6 15v-1H2.7L7 9.7 6.3 9 2 13.3V10H1v5zm4-14v1h3.3L9 6.3l.7.7L14 2.7V6h1V1z"
103590
+ })
103314
103591
  });
103315
103592
  };
103316
103593
  OpenPopupIcon.defaultProps = {
103317
103594
  xmlns: "http://www.w3.org/2000/svg",
103318
- width: "16",
103319
- height: "16",
103320
- viewBox: "0 0 32 32"
103595
+ viewBox: "0 0 16 16"
103321
103596
  };
103322
103597
 
103598
+ /**
103599
+ * @typedef { {
103600
+ * getElementLabel: (element: object) => string,
103601
+ * getTypeLabel: (element: object) => string,
103602
+ * getElementIcon: (element: object) => import('preact').Component,
103603
+ * getDocumentationRef: (element: object) => string
103604
+ * } } HeaderProvider
103605
+ */
103606
+
103607
+ /**
103608
+ * @param {Object} props
103609
+ * @param {Object} props.element,
103610
+ * @param {HeaderProvider} props.headerProvider
103611
+ */
103323
103612
  function Header(props) {
103324
103613
  const {
103325
103614
  element,
@@ -103347,11 +103636,9 @@
103347
103636
  }), u("div", {
103348
103637
  class: "bio-properties-panel-header-labels",
103349
103638
  children: [u("div", {
103350
- title: type,
103351
103639
  class: "bio-properties-panel-header-type",
103352
103640
  children: type
103353
103641
  }), label ? u("div", {
103354
- title: label,
103355
103642
  class: "bio-properties-panel-header-label",
103356
103643
  children: label
103357
103644
  }) : null]
@@ -103444,6 +103731,26 @@
103444
103731
  return getTooltipForId(id, element);
103445
103732
  }
103446
103733
 
103734
+ /**
103735
+ * @typedef {Object} TooltipProps
103736
+ * @property {Object} [parent] - Parent element ref for portal rendering
103737
+ * @property {String} [direction='right'] - Tooltip direction ( 'right', 'top')
103738
+ * @property {String} [position] - Custom CSS position override
103739
+ * @property {Number} [showDelay=250] - Delay in ms before showing tooltip on hover
103740
+ * @property {Number} [hideDelay=250] - Delay in ms before hiding tooltip when mouse leaves, to avoid multiple tooltips from being opened, this should be the same as showDelay
103741
+ * @property {*} [children] - Child elements to render inside the tooltip wrapper
103742
+ */
103743
+
103744
+ /**
103745
+ * Tooltip wrapper that provides context-based tooltip content lookup.
103746
+ * All props are forwarded to the underlying Tooltip component.
103747
+ *
103748
+ * @param {TooltipProps & {
103749
+ * forId: String,
103750
+ * value?: String|Object,
103751
+ * element?: Object
103752
+ * }} props - Shared tooltip props plus wrapper-specific ones
103753
+ */
103447
103754
  function TooltipWrapper(props) {
103448
103755
  const {
103449
103756
  forId,
@@ -103460,35 +103767,77 @@
103460
103767
  forId: `bio-properties-panel-${forId}`
103461
103768
  });
103462
103769
  }
103770
+
103771
+ /**
103772
+ * @param {TooltipProps & {
103773
+ * forId: String,
103774
+ * value: String|Object
103775
+ * }} props
103776
+ */
103463
103777
  function Tooltip(props) {
103464
103778
  const {
103465
103779
  forId,
103466
103780
  value,
103467
103781
  parent,
103468
103782
  direction = 'right',
103469
- position
103783
+ position,
103784
+ showDelay = 250,
103785
+ hideDelay = 250
103470
103786
  } = props;
103471
103787
  const [visible, setVisible] = h(false);
103472
-
103473
- // Tooltip will be shown after SHOW_DELAY ms from hovering over the source element.
103474
- const SHOW_DELAY = 200;
103475
- let timeout = null;
103788
+ const showTimeoutRef = _(null);
103789
+ const hideTimeoutRef = _(null);
103476
103790
  const wrapperRef = _(null);
103477
103791
  const tooltipRef = _(null);
103478
103792
  const show = (_, delay) => {
103793
+ clearTimeout(showTimeoutRef.current);
103794
+ clearTimeout(hideTimeoutRef.current);
103479
103795
  if (visible) return;
103480
103796
  if (delay) {
103481
- timeout = setTimeout(() => {
103797
+ showTimeoutRef.current = setTimeout(() => {
103482
103798
  setVisible(true);
103483
- }, SHOW_DELAY);
103799
+ }, showDelay);
103484
103800
  } else {
103485
103801
  setVisible(true);
103486
103802
  }
103487
103803
  };
103488
- const hide = () => {
103489
- clearTimeout(timeout);
103490
- setVisible(false);
103804
+ const handleWrapperMouseEnter = e => {
103805
+ show(e, true);
103806
+ };
103807
+ const hide = (delay = false) => {
103808
+ clearTimeout(showTimeoutRef.current);
103809
+ clearTimeout(hideTimeoutRef.current);
103810
+ if (delay) {
103811
+ hideTimeoutRef.current = setTimeout(() => {
103812
+ setVisible(false);
103813
+ }, hideDelay);
103814
+ } else {
103815
+ setVisible(false);
103816
+ }
103491
103817
  };
103818
+
103819
+ // Cleanup timeouts on unmount
103820
+ p(() => {
103821
+ return () => {
103822
+ clearTimeout(showTimeoutRef.current);
103823
+ clearTimeout(hideTimeoutRef.current);
103824
+ };
103825
+ }, []);
103826
+
103827
+ // Handle click outside to close tooltip for non-focusable elements
103828
+ p(() => {
103829
+ if (!visible) return;
103830
+ const handleClickOutside = e => {
103831
+ // If clicking outside both the wrapper and tooltip, hide it
103832
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target) && tooltipRef.current && !tooltipRef.current.contains(e.target)) {
103833
+ hide(false);
103834
+ }
103835
+ };
103836
+ document.addEventListener('mousedown', handleClickOutside);
103837
+ return () => {
103838
+ document.removeEventListener('mousedown', handleClickOutside);
103839
+ };
103840
+ }, [visible, hide]);
103492
103841
  const handleMouseLeave = ({
103493
103842
  relatedTarget
103494
103843
  }) => {
@@ -103496,23 +103845,32 @@
103496
103845
  if (relatedTarget === wrapperRef.current || relatedTarget === tooltipRef.current || relatedTarget?.parentElement === tooltipRef.current) {
103497
103846
  return;
103498
103847
  }
103499
- hide();
103848
+ const selection = window.getSelection();
103849
+ if (selection && selection.toString().length > 0) {
103850
+ // Check if selection is within tooltip content
103851
+ const selectionRange = selection.getRangeAt(0);
103852
+ if (tooltipRef.current?.contains(selectionRange.commonAncestorContainer) || tooltipRef.current?.contains(selection.anchorNode) || tooltipRef.current?.contains(selection.focusNode)) {
103853
+ return; // Keep tooltip open during text selection
103854
+ }
103855
+ }
103856
+ hide(true);
103857
+ };
103858
+ const handleTooltipMouseEnter = () => {
103859
+ clearTimeout(hideTimeoutRef.current);
103500
103860
  };
103501
103861
  const handleFocusOut = e => {
103502
103862
  const {
103503
- target
103863
+ relatedTarget
103504
103864
  } = e;
103505
103865
 
103506
- // Don't hide the tooltip if the wrapper or the tooltip itself is clicked.
103507
- const isHovered = target.matches(':hover') || tooltipRef.current?.matches(':hover');
103508
- if (target === wrapperRef.current && isHovered) {
103509
- e.stopPropagation();
103866
+ // Don't hide if focus moved to the tooltip or another element within the wrapper
103867
+ if (tooltipRef.current?.contains(relatedTarget) || wrapperRef.current?.contains(relatedTarget)) {
103510
103868
  return;
103511
103869
  }
103512
- hide();
103870
+ hide(false);
103513
103871
  };
103514
103872
  const hideTooltipViaEscape = e => {
103515
- e.code === 'Escape' && hide();
103873
+ e.code === 'Escape' && hide(false);
103516
103874
  };
103517
103875
  const renderTooltip = () => {
103518
103876
  return u("div", {
@@ -103523,6 +103881,7 @@
103523
103881
  style: position || getTooltipPosition(wrapperRef.current),
103524
103882
  ref: tooltipRef,
103525
103883
  onClick: e => e.stopPropagation(),
103884
+ onMouseEnter: handleTooltipMouseEnter,
103526
103885
  onMouseLeave: handleMouseLeave,
103527
103886
  children: [u("div", {
103528
103887
  class: "bio-properties-panel-tooltip-content",
@@ -103536,7 +103895,7 @@
103536
103895
  class: "bio-properties-panel-tooltip-wrapper",
103537
103896
  tabIndex: "0",
103538
103897
  ref: wrapperRef,
103539
- onMouseEnter: e => show(e, true),
103898
+ onMouseEnter: handleWrapperMouseEnter,
103540
103899
  onMouseLeave: handleMouseLeave,
103541
103900
  onFocus: show,
103542
103901
  onBlur: handleFocusOut,
@@ -103818,6 +104177,9 @@
103818
104177
  return visible;
103819
104178
  }
103820
104179
 
104180
+ /**
104181
+ * @param {import('../PropertiesPanel').GroupDefinition} props
104182
+ */
103821
104183
  function Group(props) {
103822
104184
  const {
103823
104185
  element,
@@ -103872,8 +104234,6 @@
103872
104234
  class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
103873
104235
  onClick: toggleOpen,
103874
104236
  children: [u("div", {
103875
- title: props.tooltip ? null : label,
103876
- "data-title": label,
103877
104237
  class: "bio-properties-panel-group-header-title",
103878
104238
  children: u(TooltipWrapper, {
103879
104239
  value: props.tooltip,
@@ -104226,6 +104586,12 @@
104226
104586
  }, deps);
104227
104587
  }
104228
104588
 
104589
+ /**
104590
+ * @param {Object} props
104591
+ * @param {Object} props.element
104592
+ * @param {String} props.forId - id of the entry the description is used for
104593
+ * @param {String} props.value
104594
+ */
104229
104595
  function Description(props) {
104230
104596
  const {
104231
104597
  element,
@@ -104357,6 +104723,15 @@
104357
104723
  return `bio-properties-panel-${id}`;
104358
104724
  }
104359
104725
 
104726
+ /**
104727
+ * Button to open popups.
104728
+ *
104729
+ * @param {Object} props
104730
+ * @param {Function} props.onClick - Callback to trigger when the button is clicked.
104731
+ * @param {string} [props.title] - Tooltip text for the button.
104732
+ * @param {boolean} [props.disabled] - Whether the button is disabled.
104733
+ * @param {string} [props.className] - Additional class names for the button.
104734
+ */
104360
104735
  function OpenPopupButton({
104361
104736
  onClick,
104362
104737
  title = 'Open pop-up editor'
@@ -104502,6 +104877,7 @@
104502
104877
  enableGutters,
104503
104878
  value,
104504
104879
  onInput,
104880
+ onKeyDown: onKeyDownProp = noop$4,
104505
104881
  onFeelToggle = noop$4,
104506
104882
  onLint = noop$4,
104507
104883
  onOpenPopup = noop$4,
@@ -104534,6 +104910,8 @@
104534
104910
  * - AND the cursor is at the beginning of the input
104535
104911
  */
104536
104912
  const onKeyDown = e => {
104913
+ // Call parent onKeyDown handler first
104914
+ onKeyDownProp(e);
104537
104915
  if (e.key !== 'Backspace' || !editor) {
104538
104916
  return;
104539
104917
  }
@@ -104606,6 +104984,22 @@
104606
104984
  });
104607
104985
  });
104608
104986
 
104987
+ /**
104988
+ * @param {KeyboardEvent} event
104989
+ * @return {boolean}
104990
+ */
104991
+ function isCmd(event) {
104992
+ // ensure we don't react to AltGr
104993
+ // (mapped to CTRL + ALT)
104994
+ if (event.altKey) {
104995
+ return false;
104996
+ }
104997
+ return event.ctrlKey || event.metaKey;
104998
+ }
104999
+ function isCmdWithChar(event) {
105000
+ return isCmd(event) && event.key.length === 1 && /^[a-zA-Z]$/.test(event.key);
105001
+ }
105002
+
104609
105003
  function ToggleSwitch(props) {
104610
105004
  const {
104611
105005
  id,
@@ -104753,6 +105147,7 @@
104753
105147
  id,
104754
105148
  disabled,
104755
105149
  onInput,
105150
+ onKeyDown,
104756
105151
  value,
104757
105152
  onFocus,
104758
105153
  onBlur,
@@ -104788,6 +105183,7 @@
104788
105183
  class: "bio-properties-panel-input",
104789
105184
  onInput: e => onInput(e.target.value),
104790
105185
  onFocus: onFocus,
105186
+ onKeyDown: onKeyDown,
104791
105187
  onBlur: onBlur,
104792
105188
  placeholder: placeholder,
104793
105189
  value: value || ''
@@ -104960,6 +105356,24 @@
104960
105356
  return `bio-properties-panel-${id}`;
104961
105357
  }
104962
105358
 
105359
+ /**
105360
+ * @typedef { { value: string, label: string, disabled: boolean, children: { value: string, label: string, disabled: boolean } } } Option
105361
+ */
105362
+
105363
+ /**
105364
+ * Provides basic select input.
105365
+ *
105366
+ * @param {object} props
105367
+ * @param {string} props.id
105368
+ * @param {string[]} props.path
105369
+ * @param {string} props.label
105370
+ * @param {Function} props.onChange
105371
+ * @param {Function} props.onFocus
105372
+ * @param {Function} props.onBlur
105373
+ * @param {Array<Option>} [props.options]
105374
+ * @param {string} props.value
105375
+ * @param {boolean} [props.disabled]
105376
+ */
104963
105377
  function Select(props) {
104964
105378
  const {
104965
105379
  id,
@@ -105126,12 +105540,13 @@
105126
105540
  id,
105127
105541
  label,
105128
105542
  debounce,
105129
- onInput,
105543
+ onInput: commitValue,
105130
105544
  value = '',
105131
105545
  disabled,
105132
105546
  monospace,
105133
105547
  onFocus,
105134
105548
  onBlur,
105549
+ onPaste,
105135
105550
  autoResize = true,
105136
105551
  placeholder,
105137
105552
  rows = autoResize ? 1 : 2,
@@ -105139,16 +105554,16 @@
105139
105554
  } = props;
105140
105555
  const [localValue, setLocalValue] = h(value);
105141
105556
  const ref = useShowEntryEvent(id);
105557
+ const onInput = T$1(newValue => {
105558
+ const newModelValue = newValue === '' ? undefined : newValue;
105559
+ commitValue(newModelValue);
105560
+ }, [commitValue]);
105142
105561
  const visible = useElementVisible(ref.current);
105143
105562
 
105144
105563
  /**
105145
105564
  * @type { import('min-dash').DebouncedFunction }
105146
105565
  */
105147
- const handleInputCallback = useDebounce(onInput, debounce);
105148
- const handleInput = newValue => {
105149
- const newModelValue = newValue === '' ? undefined : newValue;
105150
- handleInputCallback(newModelValue);
105151
- };
105566
+ const handleInput = useDebounce(onInput, debounce);
105152
105567
  const handleLocalInput = e => {
105153
105568
  autoResize && resizeToContents(e.target);
105154
105569
  if (e.target.value === localValue) {
@@ -105161,11 +105576,40 @@
105161
105576
  const trimmedValue = e.target.value.trim();
105162
105577
 
105163
105578
  // trim and commit on blur
105579
+ handleInput.cancel?.();
105164
105580
  onInput(trimmedValue);
105581
+ setLocalValue(trimmedValue);
105165
105582
  if (onBlur) {
105166
105583
  onBlur(e);
105167
105584
  }
105168
105585
  };
105586
+ const handleOnPaste = e => {
105587
+ const input = e.target;
105588
+ const isFieldEmpty = !input.value;
105589
+ const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
105590
+
105591
+ // Trim and handle paste if field is empty or all content is selected
105592
+ if (isFieldEmpty || isAllSelected) {
105593
+ const trimmedValue = e.clipboardData.getData('text').trim();
105594
+ setLocalValue(trimmedValue);
105595
+ handleInput(trimmedValue);
105596
+ if (onPaste) {
105597
+ onPaste(e);
105598
+ }
105599
+ e.preventDefault();
105600
+ return;
105601
+ }
105602
+
105603
+ // Allow default paste behavior for normal text editing
105604
+ if (onPaste) {
105605
+ onPaste(e);
105606
+ }
105607
+ };
105608
+ const handleOnKeyDown = e => {
105609
+ if (isCmdWithChar(e)) {
105610
+ handleInput.flush();
105611
+ }
105612
+ };
105169
105613
  y(() => {
105170
105614
  autoResize && resizeToContents(ref.current);
105171
105615
  }, []);
@@ -105197,7 +105641,9 @@
105197
105641
  class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
105198
105642
  onInput: handleLocalInput,
105199
105643
  onFocus: onFocus,
105644
+ onKeyDown: handleOnKeyDown,
105200
105645
  onBlur: handleOnBlur,
105646
+ onPaste: handleOnPaste,
105201
105647
  placeholder: placeholder,
105202
105648
  rows: rows,
105203
105649
  value: localValue,
@@ -105218,6 +105664,7 @@
105218
105664
  * @param {Function} props.setValue
105219
105665
  * @param {Function} props.onFocus
105220
105666
  * @param {Function} props.onBlur
105667
+ * @param {Function} props.onPaste
105221
105668
  * @param {number} props.rows
105222
105669
  * @param {boolean} props.monospace
105223
105670
  * @param {Function} [props.validate]
@@ -105238,6 +105685,7 @@
105238
105685
  validate,
105239
105686
  onFocus,
105240
105687
  onBlur,
105688
+ onPaste,
105241
105689
  placeholder,
105242
105690
  autoResize,
105243
105691
  tooltip
@@ -105273,6 +105721,7 @@
105273
105721
  onInput: onInput,
105274
105722
  onFocus: onFocus,
105275
105723
  onBlur: onBlur,
105724
+ onPaste: onPaste,
105276
105725
  rows: rows,
105277
105726
  debounce: debounce,
105278
105727
  monospace: monospace,
@@ -105307,32 +105756,57 @@
105307
105756
  disabled = false,
105308
105757
  id,
105309
105758
  label,
105310
- onInput,
105759
+ onInput: commitValue,
105311
105760
  onFocus,
105312
105761
  onBlur,
105762
+ onPaste,
105313
105763
  placeholder,
105314
105764
  value = '',
105315
105765
  tooltip
105316
105766
  } = props;
105317
105767
  const [localValue, setLocalValue] = h(value || '');
105318
105768
  const ref = useShowEntryEvent(id);
105769
+ const onInput = T$1(newValue => {
105770
+ const newModelValue = newValue === '' ? undefined : newValue;
105771
+ commitValue(newModelValue);
105772
+ }, [commitValue]);
105319
105773
 
105320
105774
  /**
105321
105775
  * @type { import('min-dash').DebouncedFunction }
105322
105776
  */
105323
- const handleInputCallback = useDebounce(onInput, debounce);
105777
+ const handleInput = useDebounce(onInput, debounce);
105324
105778
  const handleOnBlur = e => {
105325
105779
  const trimmedValue = e.target.value.trim();
105326
105780
 
105327
105781
  // trim and commit on blur
105782
+ handleInput.cancel?.();
105328
105783
  onInput(trimmedValue);
105784
+ setLocalValue(trimmedValue);
105329
105785
  if (onBlur) {
105330
105786
  onBlur(e);
105331
105787
  }
105332
105788
  };
105333
- const handleInput = newValue => {
105334
- const newModelValue = newValue === '' ? undefined : newValue;
105335
- handleInputCallback(newModelValue);
105789
+ const handleOnPaste = e => {
105790
+ const input = e.target;
105791
+ const isFieldEmpty = !input.value;
105792
+ const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
105793
+
105794
+ // Trim and handle paste if field is empty or all content is selected (overwrite)
105795
+ if (isFieldEmpty || isAllSelected) {
105796
+ const trimmedValue = e.clipboardData.getData('text').trim();
105797
+ setLocalValue(trimmedValue);
105798
+ handleInput(trimmedValue);
105799
+ if (onPaste) {
105800
+ onPaste(e);
105801
+ }
105802
+ e.preventDefault();
105803
+ return;
105804
+ }
105805
+
105806
+ // Allow default paste behavior for normal text editing
105807
+ if (onPaste) {
105808
+ onPaste(e);
105809
+ }
105336
105810
  };
105337
105811
  const handleLocalInput = e => {
105338
105812
  if (e.target.value === localValue) {
@@ -105347,6 +105821,11 @@
105347
105821
  }
105348
105822
  setLocalValue(value);
105349
105823
  }, [value]);
105824
+ const handleOnKeyDown = e => {
105825
+ if (isCmdWithChar(e)) {
105826
+ handleInput.flush();
105827
+ }
105828
+ };
105350
105829
  return u("div", {
105351
105830
  class: "bio-properties-panel-textfield",
105352
105831
  children: [u("label", {
@@ -105369,7 +105848,9 @@
105369
105848
  class: "bio-properties-panel-input",
105370
105849
  onInput: handleLocalInput,
105371
105850
  onFocus: onFocus,
105851
+ onKeyDown: handleOnKeyDown,
105372
105852
  onBlur: handleOnBlur,
105853
+ onPaste: handleOnPaste,
105373
105854
  placeholder: placeholder,
105374
105855
  value: localValue
105375
105856
  })]
@@ -105404,6 +105885,7 @@
105404
105885
  validate,
105405
105886
  onFocus,
105406
105887
  onBlur,
105888
+ onPaste,
105407
105889
  placeholder,
105408
105890
  tooltip
105409
105891
  } = props;
@@ -105439,6 +105921,7 @@
105439
105921
  onInput: onInput,
105440
105922
  onFocus: onFocus,
105441
105923
  onBlur: onBlur,
105924
+ onPaste: onPaste,
105442
105925
  placeholder: placeholder,
105443
105926
  value: value,
105444
105927
  tooltip: tooltip,
@@ -105471,7 +105954,7 @@
105471
105954
  * - If `debounceDelay` is `false`, the function executes immediately without debouncing.
105472
105955
  * - If a number is provided, the function execution is delayed by the given time in milliseconds.
105473
105956
  *
105474
- * @param { Boolean | Number } [debounceDelay=300]
105957
+ * @param { Boolean | Number } [debounceDelay=600]
105475
105958
  *
105476
105959
  * @example
105477
105960
  * const debounce = debounceInput();
@@ -105791,6 +106274,24 @@
105791
106274
  event.stopPropagation();
105792
106275
  }
105793
106276
 
106277
+ /**
106278
+ * @typedef {Object} FeelPopupProps
106279
+ * @property {string} entryId
106280
+ * @property {Function} onInput
106281
+ * @property {Function} onClose
106282
+ * @property {string} title
106283
+ * @property {'feel'|'feelers'} type
106284
+ * @property {string} value
106285
+ * @property {Array} [links]
106286
+ * @property {Array|Object} [variables]
106287
+ * @property {Object} [position]
106288
+ * @property {string} [hostLanguage]
106289
+ * @property {boolean} [singleLine]
106290
+ * @property {HTMLElement} [sourceElement]
106291
+ * @property {HTMLElement|string} [tooltipContainer]
106292
+ * @property {Object} [eventBus]
106293
+ */
106294
+
105794
106295
  const FEEL_POPUP_WIDTH = 700;
105795
106296
  const FEEL_POPUP_HEIGHT = 250;
105796
106297
 
@@ -107649,17 +108150,17 @@
107649
108150
  };
107650
108151
  }, [selectedElement]);
107651
108152
 
107652
- // (2c) root element changed
108153
+ // (2c) import done
107653
108154
  p(() => {
107654
- const onRootAdded = e => {
107655
- const element = e.element;
107656
- _update(element);
108155
+ const onImportDone = () => {
108156
+ const rootElement = canvas.getRootElement();
108157
+ _update(rootElement);
107657
108158
  };
107658
- eventBus.on('root.added', onRootAdded);
108159
+ eventBus.on('import.done', onImportDone);
107659
108160
  return () => {
107660
- eventBus.off('root.added', onRootAdded);
108161
+ eventBus.off('import.done', onImportDone);
107661
108162
  };
107662
- }, [selectedElement]);
108163
+ }, []);
107663
108164
 
107664
108165
  // (2d) provided entries changed
107665
108166
  p(() => {
@@ -108129,7 +108630,7 @@
108129
108630
  }, {
108130
108631
  id: 'cancelRemainingInstances',
108131
108632
  component: CancelRemainingInstances,
108132
- isEdited: isEdited$8
108633
+ isEdited: node => node && !node.checked // the default value is true
108133
108634
  }];
108134
108635
  }
108135
108636
  function CompletionCondition$3(props) {
@@ -109898,6 +110399,13 @@
109898
110399
  });
109899
110400
  }
109900
110401
 
110402
+ /**
110403
+ * @typedef { import('@bpmn-io/properties-panel').EntryDefinition } Entry
110404
+ */
110405
+
110406
+ /**
110407
+ * @returns {Array<Entry>} entries
110408
+ */
109901
110409
  function TimerProps$2(props) {
109902
110410
  const {
109903
110411
  element,