sequential-workflow-designer 0.31.0 → 0.33.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.
package/README.md CHANGED
@@ -106,10 +106,10 @@ Add the below code to your head section in HTML document.
106
106
  ```html
107
107
  <head>
108
108
  ...
109
- <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.31.0/css/designer.css" rel="stylesheet">
110
- <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.31.0/css/designer-light.css" rel="stylesheet">
111
- <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.31.0/css/designer-dark.css" rel="stylesheet">
112
- <script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.31.0/dist/index.umd.js"></script>
109
+ <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.33.0/css/designer.css" rel="stylesheet">
110
+ <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.33.0/css/designer-light.css" rel="stylesheet">
111
+ <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.33.0/css/designer-dark.css" rel="stylesheet">
112
+ <script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.33.0/dist/index.umd.js"></script>
113
113
  ```
114
114
 
115
115
  Call the designer by:
package/dist/index.umd.js CHANGED
@@ -247,8 +247,7 @@
247
247
  }
248
248
  tryDelete() {
249
249
  if (this.canDelete() && this.state.selectedStepId) {
250
- this.stateModifier.tryDelete(this.state.selectedStepId);
251
- return true;
250
+ return this.stateModifier.tryDeleteById(this.state.selectedStepId);
252
251
  }
253
252
  return false;
254
253
  }
@@ -256,7 +255,7 @@
256
255
  return (!!this.state.selectedStepId &&
257
256
  !this.state.isReadonly &&
258
257
  !this.state.isDragging &&
259
- this.stateModifier.isDeletable(this.state.selectedStepId));
258
+ this.stateModifier.isDeletableById(this.state.selectedStepId));
260
259
  }
261
260
  }
262
261
 
@@ -397,14 +396,14 @@
397
396
  }
398
397
 
399
398
  class DragStepView {
400
- static create(step, theme, componentContext) {
399
+ static create(step, isAttached, theme, componentContext) {
401
400
  var _a;
402
401
  const body = (_a = componentContext.shadowRoot) !== null && _a !== void 0 ? _a : document.body;
403
402
  const layer = Dom.element('div', {
404
403
  class: `sqd-drag sqd-theme-${theme}`
405
404
  });
406
405
  body.appendChild(layer);
407
- const component = componentContext.services.draggedComponent.create(layer, step, componentContext);
406
+ const component = componentContext.services.draggedComponent.create(layer, step, isAttached, componentContext);
408
407
  return new DragStepView(component, layer, body);
409
408
  }
410
409
  constructor(component, layer, body) {
@@ -466,29 +465,30 @@
466
465
  }
467
466
 
468
467
  class DragStepBehavior {
469
- static create(designerContext, step, draggedStepComponent) {
470
- const view = DragStepView.create(step, designerContext.theme, designerContext.componentContext);
471
- return new DragStepBehavior(view, designerContext.workspaceController, designerContext.placeholderController, designerContext.state, step, designerContext.stateModifier, draggedStepComponent);
468
+ static create(designerContext, step, attachedStepComponent) {
469
+ const isAttached = Boolean(attachedStepComponent);
470
+ const view = DragStepView.create(step, isAttached, designerContext.theme, designerContext.componentContext);
471
+ return new DragStepBehavior(view, designerContext.workspaceController, designerContext.placeholderController, designerContext.state, step, designerContext.stateModifier, attachedStepComponent);
472
472
  }
473
- constructor(view, workspaceController, placeholderController, designerState, step, stateModifier, draggedStepComponent) {
473
+ constructor(view, workspaceController, placeholderController, designerState, step, stateModifier, attachedStepComponent) {
474
474
  this.view = view;
475
475
  this.workspaceController = workspaceController;
476
476
  this.placeholderController = placeholderController;
477
477
  this.designerState = designerState;
478
478
  this.step = step;
479
479
  this.stateModifier = stateModifier;
480
- this.draggedStepComponent = draggedStepComponent;
480
+ this.attachedStepComponent = attachedStepComponent;
481
481
  }
482
482
  onStart(position) {
483
483
  let offset = null;
484
- if (this.draggedStepComponent) {
485
- this.draggedStepComponent.setIsDisabled(true);
486
- this.draggedStepComponent.setIsDragging(true);
487
- const hasSameSize = this.draggedStepComponent.view.width === this.view.component.width &&
488
- this.draggedStepComponent.view.height === this.view.component.height;
484
+ if (this.attachedStepComponent) {
485
+ this.attachedStepComponent.setIsDisabled(true);
486
+ this.attachedStepComponent.setIsDragging(true);
487
+ const hasSameSize = this.attachedStepComponent.view.width === this.view.component.width &&
488
+ this.attachedStepComponent.view.height === this.view.component.height;
489
489
  if (hasSameSize) {
490
490
  // Mouse cursor will be positioned on the same place as the source component.
491
- const pagePosition = this.draggedStepComponent.view.getClientPosition();
491
+ const pagePosition = this.attachedStepComponent.view.getClientPosition();
492
492
  offset = position.subtract(pagePosition);
493
493
  }
494
494
  }
@@ -498,7 +498,7 @@
498
498
  }
499
499
  this.view.setPosition(position.subtract(offset));
500
500
  this.designerState.setIsDragging(true);
501
- const { placeholders, components } = this.resolvePlaceholders(this.draggedStepComponent);
501
+ const { placeholders, components } = this.resolvePlaceholders(this.attachedStepComponent);
502
502
  this.state = {
503
503
  placeholders,
504
504
  components,
@@ -537,17 +537,17 @@
537
537
  this.designerState.setIsDragging(false);
538
538
  let modified = false;
539
539
  if (!interrupt && this.currentPlaceholder) {
540
- if (this.draggedStepComponent) {
541
- modified = this.stateModifier.tryMove(this.draggedStepComponent.parentSequence, this.draggedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
540
+ if (this.attachedStepComponent) {
541
+ modified = this.stateModifier.tryMove(this.attachedStepComponent.parentSequence, this.attachedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
542
542
  }
543
543
  else {
544
544
  modified = this.stateModifier.tryInsert(this.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
545
545
  }
546
546
  }
547
547
  if (!modified) {
548
- if (this.draggedStepComponent) {
549
- this.draggedStepComponent.setIsDisabled(false);
550
- this.draggedStepComponent.setIsDragging(false);
548
+ if (this.attachedStepComponent) {
549
+ this.attachedStepComponent.setIsDisabled(false);
550
+ this.attachedStepComponent.setIsDragging(false);
551
551
  }
552
552
  if (this.currentPlaceholder) {
553
553
  this.currentPlaceholder.setIsHover(false);
@@ -3096,30 +3096,56 @@
3096
3096
  isSelectable(step, parentSequence) {
3097
3097
  return this.configuration.isSelectable ? this.configuration.isSelectable(step, parentSequence) : true;
3098
3098
  }
3099
- trySelectStep(step, parentSequence) {
3100
- if (this.isSelectable(step, parentSequence)) {
3101
- this.state.setSelectedStepId(step.id);
3099
+ isSelectableById(stepId) {
3100
+ if (this.configuration.isSelectable) {
3101
+ const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3102
+ return this.configuration.isSelectable(result.step, result.parentSequence);
3103
+ }
3104
+ return true;
3105
+ }
3106
+ canUnselectSelectedStep() {
3107
+ if (this.state.selectedStepId) {
3108
+ if (this.configuration.canUnselectStep) {
3109
+ const result = this.definitionWalker.getParentSequence(this.state.definition, this.state.selectedStepId);
3110
+ return this.configuration.canUnselectStep(result.step, result.parentSequence);
3111
+ }
3102
3112
  return true;
3103
3113
  }
3104
- return false;
3114
+ return null;
3105
3115
  }
3106
- trySelectStepById(stepId) {
3107
- if (this.configuration.isSelectable) {
3108
- const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3109
- this.trySelectStep(result.step, result.parentSequence);
3116
+ /**
3117
+ * @description Check the `isSelectable` callback before calling this method.
3118
+ */
3119
+ trySelectStepById(stepIdOrNull) {
3120
+ const can = this.canUnselectSelectedStep();
3121
+ if (can === true || can === null) {
3122
+ this.state.setSelectedStepId(stepIdOrNull);
3123
+ return true;
3110
3124
  }
3111
- else {
3112
- this.state.setSelectedStepId(stepId);
3125
+ this.state.notifyStepUnselectionBlocked(stepIdOrNull);
3126
+ return false;
3127
+ }
3128
+ tryResetSelectedStep() {
3129
+ let stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
3130
+ if (stepIdOrNull && !this.isSelectableById(stepIdOrNull)) {
3131
+ stepIdOrNull = null;
3113
3132
  }
3133
+ this.trySelectStepById(stepIdOrNull);
3114
3134
  }
3115
- isDeletable(stepId) {
3135
+ isDeletable(step, parentSequence) {
3136
+ return this.configuration.isDeletable ? this.configuration.isDeletable(step, parentSequence) : true;
3137
+ }
3138
+ isDeletableById(stepId) {
3116
3139
  if (this.configuration.isDeletable) {
3117
3140
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3118
3141
  return this.configuration.isDeletable(result.step, result.parentSequence);
3119
3142
  }
3120
3143
  return true;
3121
3144
  }
3122
- tryDelete(stepId) {
3145
+ /**
3146
+ * @description Check the `isDeletable` callback before calling this method.
3147
+ */
3148
+ tryDeleteById(stepId) {
3123
3149
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3124
3150
  const canDeleteStep = this.configuration.canDeleteStep
3125
3151
  ? this.configuration.canDeleteStep(result.step, result.parentSequence)
@@ -3139,7 +3165,7 @@
3139
3165
  }
3140
3166
  SequenceModifier.insertStep(step, targetSequence, targetIndex);
3141
3167
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepInserted, step.id);
3142
- if (!this.configuration.isAutoSelectDisabled) {
3168
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3143
3169
  this.trySelectStepById(step.id);
3144
3170
  }
3145
3171
  return true;
@@ -3160,14 +3186,17 @@
3160
3186
  }
3161
3187
  apply();
3162
3188
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepMoved, step.id);
3163
- if (!this.configuration.isAutoSelectDisabled) {
3164
- this.trySelectStep(step, targetSequence);
3189
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3190
+ this.trySelectStepById(step.id);
3165
3191
  }
3166
3192
  return true;
3167
3193
  }
3168
3194
  isDuplicable(step, parentSequence) {
3169
3195
  return this.configuration.isDuplicable ? this.configuration.isDuplicable(step, parentSequence) : false;
3170
3196
  }
3197
+ /**
3198
+ * @description Check the `isDuplicable` callback before calling this method.
3199
+ */
3171
3200
  tryDuplicate(step, parentSequence) {
3172
3201
  const duplicator = new StepDuplicator(this.uidGenerator, this.definitionWalker);
3173
3202
  const index = parentSequence.indexOf(step);
@@ -3194,6 +3223,7 @@
3194
3223
  this.isEditorCollapsed = isEditorCollapsed;
3195
3224
  this.onViewportChanged = new SimpleEvent();
3196
3225
  this.onSelectedStepIdChanged = new SimpleEvent();
3226
+ this.onStepUnselectionBlocked = new SimpleEvent();
3197
3227
  this.onFolderPathChanged = new SimpleEvent();
3198
3228
  this.onIsReadonlyChanged = new SimpleEvent();
3199
3229
  this.onIsDraggingChanged = new SimpleEvent();
@@ -3234,6 +3264,9 @@
3234
3264
  notifyDefinitionChanged(changeType, stepId) {
3235
3265
  this.onDefinitionChanged.forward({ changeType, stepId });
3236
3266
  }
3267
+ notifyStepUnselectionBlocked(stepId) {
3268
+ this.onStepUnselectionBlocked.forward(stepId);
3269
+ }
3237
3270
  setViewport(viewport) {
3238
3271
  this.viewport = viewport;
3239
3272
  this.onViewportChanged.forward(viewport);
@@ -3625,24 +3658,23 @@
3625
3658
  this.stateModifier = stateModifier;
3626
3659
  }
3627
3660
  onStart() {
3628
- if (this.resetSelectedStep) {
3629
- const stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
3630
- if (stepIdOrNull) {
3631
- this.stateModifier.trySelectStepById(stepIdOrNull);
3632
- }
3633
- else {
3634
- this.state.setSelectedStepId(null);
3635
- }
3636
- }
3661
+ // Nothing to do.
3637
3662
  }
3638
3663
  onMove(delta) {
3664
+ this.lastDelta = delta;
3639
3665
  this.state.setViewport({
3640
3666
  position: this.startPosition.subtract(delta),
3641
3667
  scale: this.state.viewport.scale
3642
3668
  });
3643
3669
  }
3644
3670
  onEnd() {
3645
- // Nothing to do.
3671
+ if (this.resetSelectedStep) {
3672
+ const distance = this.lastDelta ? this.lastDelta.distance() : 0;
3673
+ if (distance > 2) {
3674
+ return;
3675
+ }
3676
+ this.stateModifier.tryResetSelectedStep();
3677
+ }
3646
3678
  }
3647
3679
  }
3648
3680
 
@@ -3667,7 +3699,7 @@
3667
3699
  if (delta.distance() > 2) {
3668
3700
  const canDrag = !this.state.isReadonly && !this.isDragDisabled;
3669
3701
  if (canDrag) {
3670
- this.state.setSelectedStepId(null);
3702
+ this.stateModifier.tryResetSelectedStep();
3671
3703
  return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
3672
3704
  }
3673
3705
  else {
@@ -3679,9 +3711,12 @@
3679
3711
  if (interrupt) {
3680
3712
  return;
3681
3713
  }
3682
- if (!this.stateModifier.trySelectStep(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3683
- // If we cannot select the step, we clear the selection.
3684
- this.state.setSelectedStepId(null);
3714
+ if (this.stateModifier.isSelectable(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3715
+ this.stateModifier.trySelectStepById(this.pressedStepComponent.step.id);
3716
+ }
3717
+ else {
3718
+ // If the step is not selectable, we try to reset the selection.
3719
+ this.stateModifier.tryResetSelectedStep();
3685
3720
  }
3686
3721
  return new SelectStepBehaviorEndToken(this.pressedStepComponent.step.id, Date.now());
3687
3722
  }
@@ -3916,7 +3951,7 @@
3916
3951
  label: this.i18n('contextMenu.unselect', 'Unselect'),
3917
3952
  order: 10,
3918
3953
  callback: () => {
3919
- this.state.setSelectedStepId(null);
3954
+ this.stateModifier.tryResetSelectedStep();
3920
3955
  }
3921
3956
  });
3922
3957
  }
@@ -3931,12 +3966,12 @@
3931
3966
  }
3932
3967
  }
3933
3968
  if (!this.state.isReadonly) {
3934
- if (this.stateModifier.isDeletable(step.id)) {
3969
+ if (this.stateModifier.isDeletable(step, parentSequence)) {
3935
3970
  items.push({
3936
3971
  label: this.i18n('contextMenu.delete', 'Delete'),
3937
3972
  order: 30,
3938
3973
  callback: () => {
3939
- this.stateModifier.tryDelete(step.id);
3974
+ this.stateModifier.tryDeleteById(step.id);
3940
3975
  }
3941
3976
  });
3942
3977
  }
@@ -4276,7 +4311,7 @@
4276
4311
 
4277
4312
  const SAFE_OFFSET = 10;
4278
4313
  class DefaultDraggedComponent {
4279
- static create(parent, step, componentContext) {
4314
+ static create(parent, step, _, componentContext) {
4280
4315
  const canvas = Dom.svg('svg');
4281
4316
  canvas.style.marginLeft = -10 + 'px';
4282
4317
  canvas.style.marginTop = -10 + 'px';
@@ -5179,6 +5214,7 @@
5179
5214
  designerContext.state.onViewportChanged.subscribe(designer.onViewportChanged.forward);
5180
5215
  designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward);
5181
5216
  designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward);
5217
+ designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward);
5182
5218
  return designer;
5183
5219
  }
5184
5220
  constructor(view, state, stateModifier, walker, historyController, api) {
@@ -5204,6 +5240,10 @@
5204
5240
  * @description Fires when the selected step has changed.
5205
5241
  */
5206
5242
  this.onSelectedStepIdChanged = new SimpleEvent();
5243
+ /**
5244
+ * @description Fires when the designer could not unselect the currently selected step due to restrictions.
5245
+ */
5246
+ this.onStepUnselectionBlocked = new SimpleEvent();
5207
5247
  /**
5208
5248
  * @description Fires when the toolbox is collapsed or expanded.
5209
5249
  */
@@ -5247,7 +5287,13 @@
5247
5287
  * @description Selects a step by the id.
5248
5288
  */
5249
5289
  selectStepById(stepId) {
5250
- this.stateModifier.trySelectStepById(stepId);
5290
+ this.state.setSelectedStepId(stepId);
5291
+ }
5292
+ /**
5293
+ * @description Unselects the selected step.
5294
+ */
5295
+ clearSelectedStep() {
5296
+ this.state.setSelectedStepId(null);
5251
5297
  }
5252
5298
  /**
5253
5299
  * @returns the current viewport.
@@ -5268,12 +5314,6 @@
5268
5314
  resetViewport() {
5269
5315
  this.api.viewport.resetViewport();
5270
5316
  }
5271
- /**
5272
- * @description Unselects the selected step.
5273
- */
5274
- clearSelectedStep() {
5275
- this.state.setSelectedStepId(null);
5276
- }
5277
5317
  /**
5278
5318
  * @description Moves the viewport to the step with the animation.
5279
5319
  */
package/lib/cjs/index.cjs CHANGED
@@ -245,8 +245,7 @@ class ControlBarApi {
245
245
  }
246
246
  tryDelete() {
247
247
  if (this.canDelete() && this.state.selectedStepId) {
248
- this.stateModifier.tryDelete(this.state.selectedStepId);
249
- return true;
248
+ return this.stateModifier.tryDeleteById(this.state.selectedStepId);
250
249
  }
251
250
  return false;
252
251
  }
@@ -254,7 +253,7 @@ class ControlBarApi {
254
253
  return (!!this.state.selectedStepId &&
255
254
  !this.state.isReadonly &&
256
255
  !this.state.isDragging &&
257
- this.stateModifier.isDeletable(this.state.selectedStepId));
256
+ this.stateModifier.isDeletableById(this.state.selectedStepId));
258
257
  }
259
258
  }
260
259
 
@@ -395,14 +394,14 @@ class PathBarApi {
395
394
  }
396
395
 
397
396
  class DragStepView {
398
- static create(step, theme, componentContext) {
397
+ static create(step, isAttached, theme, componentContext) {
399
398
  var _a;
400
399
  const body = (_a = componentContext.shadowRoot) !== null && _a !== void 0 ? _a : document.body;
401
400
  const layer = Dom.element('div', {
402
401
  class: `sqd-drag sqd-theme-${theme}`
403
402
  });
404
403
  body.appendChild(layer);
405
- const component = componentContext.services.draggedComponent.create(layer, step, componentContext);
404
+ const component = componentContext.services.draggedComponent.create(layer, step, isAttached, componentContext);
406
405
  return new DragStepView(component, layer, body);
407
406
  }
408
407
  constructor(component, layer, body) {
@@ -464,29 +463,30 @@ class PlaceholderFinder {
464
463
  }
465
464
 
466
465
  class DragStepBehavior {
467
- static create(designerContext, step, draggedStepComponent) {
468
- const view = DragStepView.create(step, designerContext.theme, designerContext.componentContext);
469
- return new DragStepBehavior(view, designerContext.workspaceController, designerContext.placeholderController, designerContext.state, step, designerContext.stateModifier, draggedStepComponent);
466
+ static create(designerContext, step, attachedStepComponent) {
467
+ const isAttached = Boolean(attachedStepComponent);
468
+ const view = DragStepView.create(step, isAttached, designerContext.theme, designerContext.componentContext);
469
+ return new DragStepBehavior(view, designerContext.workspaceController, designerContext.placeholderController, designerContext.state, step, designerContext.stateModifier, attachedStepComponent);
470
470
  }
471
- constructor(view, workspaceController, placeholderController, designerState, step, stateModifier, draggedStepComponent) {
471
+ constructor(view, workspaceController, placeholderController, designerState, step, stateModifier, attachedStepComponent) {
472
472
  this.view = view;
473
473
  this.workspaceController = workspaceController;
474
474
  this.placeholderController = placeholderController;
475
475
  this.designerState = designerState;
476
476
  this.step = step;
477
477
  this.stateModifier = stateModifier;
478
- this.draggedStepComponent = draggedStepComponent;
478
+ this.attachedStepComponent = attachedStepComponent;
479
479
  }
480
480
  onStart(position) {
481
481
  let offset = null;
482
- if (this.draggedStepComponent) {
483
- this.draggedStepComponent.setIsDisabled(true);
484
- this.draggedStepComponent.setIsDragging(true);
485
- const hasSameSize = this.draggedStepComponent.view.width === this.view.component.width &&
486
- this.draggedStepComponent.view.height === this.view.component.height;
482
+ if (this.attachedStepComponent) {
483
+ this.attachedStepComponent.setIsDisabled(true);
484
+ this.attachedStepComponent.setIsDragging(true);
485
+ const hasSameSize = this.attachedStepComponent.view.width === this.view.component.width &&
486
+ this.attachedStepComponent.view.height === this.view.component.height;
487
487
  if (hasSameSize) {
488
488
  // Mouse cursor will be positioned on the same place as the source component.
489
- const pagePosition = this.draggedStepComponent.view.getClientPosition();
489
+ const pagePosition = this.attachedStepComponent.view.getClientPosition();
490
490
  offset = position.subtract(pagePosition);
491
491
  }
492
492
  }
@@ -496,7 +496,7 @@ class DragStepBehavior {
496
496
  }
497
497
  this.view.setPosition(position.subtract(offset));
498
498
  this.designerState.setIsDragging(true);
499
- const { placeholders, components } = this.resolvePlaceholders(this.draggedStepComponent);
499
+ const { placeholders, components } = this.resolvePlaceholders(this.attachedStepComponent);
500
500
  this.state = {
501
501
  placeholders,
502
502
  components,
@@ -535,17 +535,17 @@ class DragStepBehavior {
535
535
  this.designerState.setIsDragging(false);
536
536
  let modified = false;
537
537
  if (!interrupt && this.currentPlaceholder) {
538
- if (this.draggedStepComponent) {
539
- modified = this.stateModifier.tryMove(this.draggedStepComponent.parentSequence, this.draggedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
538
+ if (this.attachedStepComponent) {
539
+ modified = this.stateModifier.tryMove(this.attachedStepComponent.parentSequence, this.attachedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
540
540
  }
541
541
  else {
542
542
  modified = this.stateModifier.tryInsert(this.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
543
543
  }
544
544
  }
545
545
  if (!modified) {
546
- if (this.draggedStepComponent) {
547
- this.draggedStepComponent.setIsDisabled(false);
548
- this.draggedStepComponent.setIsDragging(false);
546
+ if (this.attachedStepComponent) {
547
+ this.attachedStepComponent.setIsDisabled(false);
548
+ this.attachedStepComponent.setIsDragging(false);
549
549
  }
550
550
  if (this.currentPlaceholder) {
551
551
  this.currentPlaceholder.setIsHover(false);
@@ -2911,30 +2911,56 @@ class StateModifier {
2911
2911
  isSelectable(step, parentSequence) {
2912
2912
  return this.configuration.isSelectable ? this.configuration.isSelectable(step, parentSequence) : true;
2913
2913
  }
2914
- trySelectStep(step, parentSequence) {
2915
- if (this.isSelectable(step, parentSequence)) {
2916
- this.state.setSelectedStepId(step.id);
2914
+ isSelectableById(stepId) {
2915
+ if (this.configuration.isSelectable) {
2916
+ const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2917
+ return this.configuration.isSelectable(result.step, result.parentSequence);
2918
+ }
2919
+ return true;
2920
+ }
2921
+ canUnselectSelectedStep() {
2922
+ if (this.state.selectedStepId) {
2923
+ if (this.configuration.canUnselectStep) {
2924
+ const result = this.definitionWalker.getParentSequence(this.state.definition, this.state.selectedStepId);
2925
+ return this.configuration.canUnselectStep(result.step, result.parentSequence);
2926
+ }
2917
2927
  return true;
2918
2928
  }
2919
- return false;
2929
+ return null;
2920
2930
  }
2921
- trySelectStepById(stepId) {
2922
- if (this.configuration.isSelectable) {
2923
- const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2924
- this.trySelectStep(result.step, result.parentSequence);
2931
+ /**
2932
+ * @description Check the `isSelectable` callback before calling this method.
2933
+ */
2934
+ trySelectStepById(stepIdOrNull) {
2935
+ const can = this.canUnselectSelectedStep();
2936
+ if (can === true || can === null) {
2937
+ this.state.setSelectedStepId(stepIdOrNull);
2938
+ return true;
2925
2939
  }
2926
- else {
2927
- this.state.setSelectedStepId(stepId);
2940
+ this.state.notifyStepUnselectionBlocked(stepIdOrNull);
2941
+ return false;
2942
+ }
2943
+ tryResetSelectedStep() {
2944
+ let stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
2945
+ if (stepIdOrNull && !this.isSelectableById(stepIdOrNull)) {
2946
+ stepIdOrNull = null;
2928
2947
  }
2948
+ this.trySelectStepById(stepIdOrNull);
2929
2949
  }
2930
- isDeletable(stepId) {
2950
+ isDeletable(step, parentSequence) {
2951
+ return this.configuration.isDeletable ? this.configuration.isDeletable(step, parentSequence) : true;
2952
+ }
2953
+ isDeletableById(stepId) {
2931
2954
  if (this.configuration.isDeletable) {
2932
2955
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2933
2956
  return this.configuration.isDeletable(result.step, result.parentSequence);
2934
2957
  }
2935
2958
  return true;
2936
2959
  }
2937
- tryDelete(stepId) {
2960
+ /**
2961
+ * @description Check the `isDeletable` callback before calling this method.
2962
+ */
2963
+ tryDeleteById(stepId) {
2938
2964
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2939
2965
  const canDeleteStep = this.configuration.canDeleteStep
2940
2966
  ? this.configuration.canDeleteStep(result.step, result.parentSequence)
@@ -2954,7 +2980,7 @@ class StateModifier {
2954
2980
  }
2955
2981
  SequenceModifier.insertStep(step, targetSequence, targetIndex);
2956
2982
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepInserted, step.id);
2957
- if (!this.configuration.isAutoSelectDisabled) {
2983
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
2958
2984
  this.trySelectStepById(step.id);
2959
2985
  }
2960
2986
  return true;
@@ -2975,14 +3001,17 @@ class StateModifier {
2975
3001
  }
2976
3002
  apply();
2977
3003
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepMoved, step.id);
2978
- if (!this.configuration.isAutoSelectDisabled) {
2979
- this.trySelectStep(step, targetSequence);
3004
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3005
+ this.trySelectStepById(step.id);
2980
3006
  }
2981
3007
  return true;
2982
3008
  }
2983
3009
  isDuplicable(step, parentSequence) {
2984
3010
  return this.configuration.isDuplicable ? this.configuration.isDuplicable(step, parentSequence) : false;
2985
3011
  }
3012
+ /**
3013
+ * @description Check the `isDuplicable` callback before calling this method.
3014
+ */
2986
3015
  tryDuplicate(step, parentSequence) {
2987
3016
  const duplicator = new StepDuplicator(this.uidGenerator, this.definitionWalker);
2988
3017
  const index = parentSequence.indexOf(step);
@@ -3009,6 +3038,7 @@ class DesignerState {
3009
3038
  this.isEditorCollapsed = isEditorCollapsed;
3010
3039
  this.onViewportChanged = new SimpleEvent();
3011
3040
  this.onSelectedStepIdChanged = new SimpleEvent();
3041
+ this.onStepUnselectionBlocked = new SimpleEvent();
3012
3042
  this.onFolderPathChanged = new SimpleEvent();
3013
3043
  this.onIsReadonlyChanged = new SimpleEvent();
3014
3044
  this.onIsDraggingChanged = new SimpleEvent();
@@ -3049,6 +3079,9 @@ class DesignerState {
3049
3079
  notifyDefinitionChanged(changeType, stepId) {
3050
3080
  this.onDefinitionChanged.forward({ changeType, stepId });
3051
3081
  }
3082
+ notifyStepUnselectionBlocked(stepId) {
3083
+ this.onStepUnselectionBlocked.forward(stepId);
3084
+ }
3052
3085
  setViewport(viewport) {
3053
3086
  this.viewport = viewport;
3054
3087
  this.onViewportChanged.forward(viewport);
@@ -3440,24 +3473,23 @@ class MoveViewportBehavior {
3440
3473
  this.stateModifier = stateModifier;
3441
3474
  }
3442
3475
  onStart() {
3443
- if (this.resetSelectedStep) {
3444
- const stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
3445
- if (stepIdOrNull) {
3446
- this.stateModifier.trySelectStepById(stepIdOrNull);
3447
- }
3448
- else {
3449
- this.state.setSelectedStepId(null);
3450
- }
3451
- }
3476
+ // Nothing to do.
3452
3477
  }
3453
3478
  onMove(delta) {
3479
+ this.lastDelta = delta;
3454
3480
  this.state.setViewport({
3455
3481
  position: this.startPosition.subtract(delta),
3456
3482
  scale: this.state.viewport.scale
3457
3483
  });
3458
3484
  }
3459
3485
  onEnd() {
3460
- // Nothing to do.
3486
+ if (this.resetSelectedStep) {
3487
+ const distance = this.lastDelta ? this.lastDelta.distance() : 0;
3488
+ if (distance > 2) {
3489
+ return;
3490
+ }
3491
+ this.stateModifier.tryResetSelectedStep();
3492
+ }
3461
3493
  }
3462
3494
  }
3463
3495
 
@@ -3482,7 +3514,7 @@ class SelectStepBehavior {
3482
3514
  if (delta.distance() > 2) {
3483
3515
  const canDrag = !this.state.isReadonly && !this.isDragDisabled;
3484
3516
  if (canDrag) {
3485
- this.state.setSelectedStepId(null);
3517
+ this.stateModifier.tryResetSelectedStep();
3486
3518
  return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
3487
3519
  }
3488
3520
  else {
@@ -3494,9 +3526,12 @@ class SelectStepBehavior {
3494
3526
  if (interrupt) {
3495
3527
  return;
3496
3528
  }
3497
- if (!this.stateModifier.trySelectStep(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3498
- // If we cannot select the step, we clear the selection.
3499
- this.state.setSelectedStepId(null);
3529
+ if (this.stateModifier.isSelectable(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3530
+ this.stateModifier.trySelectStepById(this.pressedStepComponent.step.id);
3531
+ }
3532
+ else {
3533
+ // If the step is not selectable, we try to reset the selection.
3534
+ this.stateModifier.tryResetSelectedStep();
3500
3535
  }
3501
3536
  return new SelectStepBehaviorEndToken(this.pressedStepComponent.step.id, Date.now());
3502
3537
  }
@@ -3731,7 +3766,7 @@ class ContextMenuItemsBuilder {
3731
3766
  label: this.i18n('contextMenu.unselect', 'Unselect'),
3732
3767
  order: 10,
3733
3768
  callback: () => {
3734
- this.state.setSelectedStepId(null);
3769
+ this.stateModifier.tryResetSelectedStep();
3735
3770
  }
3736
3771
  });
3737
3772
  }
@@ -3746,12 +3781,12 @@ class ContextMenuItemsBuilder {
3746
3781
  }
3747
3782
  }
3748
3783
  if (!this.state.isReadonly) {
3749
- if (this.stateModifier.isDeletable(step.id)) {
3784
+ if (this.stateModifier.isDeletable(step, parentSequence)) {
3750
3785
  items.push({
3751
3786
  label: this.i18n('contextMenu.delete', 'Delete'),
3752
3787
  order: 30,
3753
3788
  callback: () => {
3754
- this.stateModifier.tryDelete(step.id);
3789
+ this.stateModifier.tryDeleteById(step.id);
3755
3790
  }
3756
3791
  });
3757
3792
  }
@@ -4091,7 +4126,7 @@ class DesignerView {
4091
4126
 
4092
4127
  const SAFE_OFFSET = 10;
4093
4128
  class DefaultDraggedComponent {
4094
- static create(parent, step, componentContext) {
4129
+ static create(parent, step, _, componentContext) {
4095
4130
  const canvas = Dom.svg('svg');
4096
4131
  canvas.style.marginLeft = -10 + 'px';
4097
4132
  canvas.style.marginTop = -10 + 'px';
@@ -4994,6 +5029,7 @@ class Designer {
4994
5029
  designerContext.state.onViewportChanged.subscribe(designer.onViewportChanged.forward);
4995
5030
  designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward);
4996
5031
  designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward);
5032
+ designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward);
4997
5033
  return designer;
4998
5034
  }
4999
5035
  constructor(view, state, stateModifier, walker, historyController, api) {
@@ -5019,6 +5055,10 @@ class Designer {
5019
5055
  * @description Fires when the selected step has changed.
5020
5056
  */
5021
5057
  this.onSelectedStepIdChanged = new SimpleEvent();
5058
+ /**
5059
+ * @description Fires when the designer could not unselect the currently selected step due to restrictions.
5060
+ */
5061
+ this.onStepUnselectionBlocked = new SimpleEvent();
5022
5062
  /**
5023
5063
  * @description Fires when the toolbox is collapsed or expanded.
5024
5064
  */
@@ -5062,7 +5102,13 @@ class Designer {
5062
5102
  * @description Selects a step by the id.
5063
5103
  */
5064
5104
  selectStepById(stepId) {
5065
- this.stateModifier.trySelectStepById(stepId);
5105
+ this.state.setSelectedStepId(stepId);
5106
+ }
5107
+ /**
5108
+ * @description Unselects the selected step.
5109
+ */
5110
+ clearSelectedStep() {
5111
+ this.state.setSelectedStepId(null);
5066
5112
  }
5067
5113
  /**
5068
5114
  * @returns the current viewport.
@@ -5083,12 +5129,6 @@ class Designer {
5083
5129
  resetViewport() {
5084
5130
  this.api.viewport.resetViewport();
5085
5131
  }
5086
- /**
5087
- * @description Unselects the selected step.
5088
- */
5089
- clearSelectedStep() {
5090
- this.state.setSelectedStepId(null);
5091
- }
5092
5132
  /**
5093
5133
  * @description Moves the viewport to the step with the animation.
5094
5134
  */
package/lib/esm/index.js CHANGED
@@ -244,8 +244,7 @@ class ControlBarApi {
244
244
  }
245
245
  tryDelete() {
246
246
  if (this.canDelete() && this.state.selectedStepId) {
247
- this.stateModifier.tryDelete(this.state.selectedStepId);
248
- return true;
247
+ return this.stateModifier.tryDeleteById(this.state.selectedStepId);
249
248
  }
250
249
  return false;
251
250
  }
@@ -253,7 +252,7 @@ class ControlBarApi {
253
252
  return (!!this.state.selectedStepId &&
254
253
  !this.state.isReadonly &&
255
254
  !this.state.isDragging &&
256
- this.stateModifier.isDeletable(this.state.selectedStepId));
255
+ this.stateModifier.isDeletableById(this.state.selectedStepId));
257
256
  }
258
257
  }
259
258
 
@@ -394,14 +393,14 @@ class PathBarApi {
394
393
  }
395
394
 
396
395
  class DragStepView {
397
- static create(step, theme, componentContext) {
396
+ static create(step, isAttached, theme, componentContext) {
398
397
  var _a;
399
398
  const body = (_a = componentContext.shadowRoot) !== null && _a !== void 0 ? _a : document.body;
400
399
  const layer = Dom.element('div', {
401
400
  class: `sqd-drag sqd-theme-${theme}`
402
401
  });
403
402
  body.appendChild(layer);
404
- const component = componentContext.services.draggedComponent.create(layer, step, componentContext);
403
+ const component = componentContext.services.draggedComponent.create(layer, step, isAttached, componentContext);
405
404
  return new DragStepView(component, layer, body);
406
405
  }
407
406
  constructor(component, layer, body) {
@@ -463,29 +462,30 @@ class PlaceholderFinder {
463
462
  }
464
463
 
465
464
  class DragStepBehavior {
466
- static create(designerContext, step, draggedStepComponent) {
467
- const view = DragStepView.create(step, designerContext.theme, designerContext.componentContext);
468
- return new DragStepBehavior(view, designerContext.workspaceController, designerContext.placeholderController, designerContext.state, step, designerContext.stateModifier, draggedStepComponent);
465
+ static create(designerContext, step, attachedStepComponent) {
466
+ const isAttached = Boolean(attachedStepComponent);
467
+ const view = DragStepView.create(step, isAttached, designerContext.theme, designerContext.componentContext);
468
+ return new DragStepBehavior(view, designerContext.workspaceController, designerContext.placeholderController, designerContext.state, step, designerContext.stateModifier, attachedStepComponent);
469
469
  }
470
- constructor(view, workspaceController, placeholderController, designerState, step, stateModifier, draggedStepComponent) {
470
+ constructor(view, workspaceController, placeholderController, designerState, step, stateModifier, attachedStepComponent) {
471
471
  this.view = view;
472
472
  this.workspaceController = workspaceController;
473
473
  this.placeholderController = placeholderController;
474
474
  this.designerState = designerState;
475
475
  this.step = step;
476
476
  this.stateModifier = stateModifier;
477
- this.draggedStepComponent = draggedStepComponent;
477
+ this.attachedStepComponent = attachedStepComponent;
478
478
  }
479
479
  onStart(position) {
480
480
  let offset = null;
481
- if (this.draggedStepComponent) {
482
- this.draggedStepComponent.setIsDisabled(true);
483
- this.draggedStepComponent.setIsDragging(true);
484
- const hasSameSize = this.draggedStepComponent.view.width === this.view.component.width &&
485
- this.draggedStepComponent.view.height === this.view.component.height;
481
+ if (this.attachedStepComponent) {
482
+ this.attachedStepComponent.setIsDisabled(true);
483
+ this.attachedStepComponent.setIsDragging(true);
484
+ const hasSameSize = this.attachedStepComponent.view.width === this.view.component.width &&
485
+ this.attachedStepComponent.view.height === this.view.component.height;
486
486
  if (hasSameSize) {
487
487
  // Mouse cursor will be positioned on the same place as the source component.
488
- const pagePosition = this.draggedStepComponent.view.getClientPosition();
488
+ const pagePosition = this.attachedStepComponent.view.getClientPosition();
489
489
  offset = position.subtract(pagePosition);
490
490
  }
491
491
  }
@@ -495,7 +495,7 @@ class DragStepBehavior {
495
495
  }
496
496
  this.view.setPosition(position.subtract(offset));
497
497
  this.designerState.setIsDragging(true);
498
- const { placeholders, components } = this.resolvePlaceholders(this.draggedStepComponent);
498
+ const { placeholders, components } = this.resolvePlaceholders(this.attachedStepComponent);
499
499
  this.state = {
500
500
  placeholders,
501
501
  components,
@@ -534,17 +534,17 @@ class DragStepBehavior {
534
534
  this.designerState.setIsDragging(false);
535
535
  let modified = false;
536
536
  if (!interrupt && this.currentPlaceholder) {
537
- if (this.draggedStepComponent) {
538
- modified = this.stateModifier.tryMove(this.draggedStepComponent.parentSequence, this.draggedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
537
+ if (this.attachedStepComponent) {
538
+ modified = this.stateModifier.tryMove(this.attachedStepComponent.parentSequence, this.attachedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
539
539
  }
540
540
  else {
541
541
  modified = this.stateModifier.tryInsert(this.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
542
542
  }
543
543
  }
544
544
  if (!modified) {
545
- if (this.draggedStepComponent) {
546
- this.draggedStepComponent.setIsDisabled(false);
547
- this.draggedStepComponent.setIsDragging(false);
545
+ if (this.attachedStepComponent) {
546
+ this.attachedStepComponent.setIsDisabled(false);
547
+ this.attachedStepComponent.setIsDragging(false);
548
548
  }
549
549
  if (this.currentPlaceholder) {
550
550
  this.currentPlaceholder.setIsHover(false);
@@ -2910,30 +2910,56 @@ class StateModifier {
2910
2910
  isSelectable(step, parentSequence) {
2911
2911
  return this.configuration.isSelectable ? this.configuration.isSelectable(step, parentSequence) : true;
2912
2912
  }
2913
- trySelectStep(step, parentSequence) {
2914
- if (this.isSelectable(step, parentSequence)) {
2915
- this.state.setSelectedStepId(step.id);
2913
+ isSelectableById(stepId) {
2914
+ if (this.configuration.isSelectable) {
2915
+ const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2916
+ return this.configuration.isSelectable(result.step, result.parentSequence);
2917
+ }
2918
+ return true;
2919
+ }
2920
+ canUnselectSelectedStep() {
2921
+ if (this.state.selectedStepId) {
2922
+ if (this.configuration.canUnselectStep) {
2923
+ const result = this.definitionWalker.getParentSequence(this.state.definition, this.state.selectedStepId);
2924
+ return this.configuration.canUnselectStep(result.step, result.parentSequence);
2925
+ }
2916
2926
  return true;
2917
2927
  }
2918
- return false;
2928
+ return null;
2919
2929
  }
2920
- trySelectStepById(stepId) {
2921
- if (this.configuration.isSelectable) {
2922
- const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2923
- this.trySelectStep(result.step, result.parentSequence);
2930
+ /**
2931
+ * @description Check the `isSelectable` callback before calling this method.
2932
+ */
2933
+ trySelectStepById(stepIdOrNull) {
2934
+ const can = this.canUnselectSelectedStep();
2935
+ if (can === true || can === null) {
2936
+ this.state.setSelectedStepId(stepIdOrNull);
2937
+ return true;
2924
2938
  }
2925
- else {
2926
- this.state.setSelectedStepId(stepId);
2939
+ this.state.notifyStepUnselectionBlocked(stepIdOrNull);
2940
+ return false;
2941
+ }
2942
+ tryResetSelectedStep() {
2943
+ let stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
2944
+ if (stepIdOrNull && !this.isSelectableById(stepIdOrNull)) {
2945
+ stepIdOrNull = null;
2927
2946
  }
2947
+ this.trySelectStepById(stepIdOrNull);
2928
2948
  }
2929
- isDeletable(stepId) {
2949
+ isDeletable(step, parentSequence) {
2950
+ return this.configuration.isDeletable ? this.configuration.isDeletable(step, parentSequence) : true;
2951
+ }
2952
+ isDeletableById(stepId) {
2930
2953
  if (this.configuration.isDeletable) {
2931
2954
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2932
2955
  return this.configuration.isDeletable(result.step, result.parentSequence);
2933
2956
  }
2934
2957
  return true;
2935
2958
  }
2936
- tryDelete(stepId) {
2959
+ /**
2960
+ * @description Check the `isDeletable` callback before calling this method.
2961
+ */
2962
+ tryDeleteById(stepId) {
2937
2963
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2938
2964
  const canDeleteStep = this.configuration.canDeleteStep
2939
2965
  ? this.configuration.canDeleteStep(result.step, result.parentSequence)
@@ -2953,7 +2979,7 @@ class StateModifier {
2953
2979
  }
2954
2980
  SequenceModifier.insertStep(step, targetSequence, targetIndex);
2955
2981
  this.state.notifyDefinitionChanged(DefinitionChangeType.stepInserted, step.id);
2956
- if (!this.configuration.isAutoSelectDisabled) {
2982
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
2957
2983
  this.trySelectStepById(step.id);
2958
2984
  }
2959
2985
  return true;
@@ -2974,14 +3000,17 @@ class StateModifier {
2974
3000
  }
2975
3001
  apply();
2976
3002
  this.state.notifyDefinitionChanged(DefinitionChangeType.stepMoved, step.id);
2977
- if (!this.configuration.isAutoSelectDisabled) {
2978
- this.trySelectStep(step, targetSequence);
3003
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3004
+ this.trySelectStepById(step.id);
2979
3005
  }
2980
3006
  return true;
2981
3007
  }
2982
3008
  isDuplicable(step, parentSequence) {
2983
3009
  return this.configuration.isDuplicable ? this.configuration.isDuplicable(step, parentSequence) : false;
2984
3010
  }
3011
+ /**
3012
+ * @description Check the `isDuplicable` callback before calling this method.
3013
+ */
2985
3014
  tryDuplicate(step, parentSequence) {
2986
3015
  const duplicator = new StepDuplicator(this.uidGenerator, this.definitionWalker);
2987
3016
  const index = parentSequence.indexOf(step);
@@ -3008,6 +3037,7 @@ class DesignerState {
3008
3037
  this.isEditorCollapsed = isEditorCollapsed;
3009
3038
  this.onViewportChanged = new SimpleEvent();
3010
3039
  this.onSelectedStepIdChanged = new SimpleEvent();
3040
+ this.onStepUnselectionBlocked = new SimpleEvent();
3011
3041
  this.onFolderPathChanged = new SimpleEvent();
3012
3042
  this.onIsReadonlyChanged = new SimpleEvent();
3013
3043
  this.onIsDraggingChanged = new SimpleEvent();
@@ -3048,6 +3078,9 @@ class DesignerState {
3048
3078
  notifyDefinitionChanged(changeType, stepId) {
3049
3079
  this.onDefinitionChanged.forward({ changeType, stepId });
3050
3080
  }
3081
+ notifyStepUnselectionBlocked(stepId) {
3082
+ this.onStepUnselectionBlocked.forward(stepId);
3083
+ }
3051
3084
  setViewport(viewport) {
3052
3085
  this.viewport = viewport;
3053
3086
  this.onViewportChanged.forward(viewport);
@@ -3439,24 +3472,23 @@ class MoveViewportBehavior {
3439
3472
  this.stateModifier = stateModifier;
3440
3473
  }
3441
3474
  onStart() {
3442
- if (this.resetSelectedStep) {
3443
- const stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
3444
- if (stepIdOrNull) {
3445
- this.stateModifier.trySelectStepById(stepIdOrNull);
3446
- }
3447
- else {
3448
- this.state.setSelectedStepId(null);
3449
- }
3450
- }
3475
+ // Nothing to do.
3451
3476
  }
3452
3477
  onMove(delta) {
3478
+ this.lastDelta = delta;
3453
3479
  this.state.setViewport({
3454
3480
  position: this.startPosition.subtract(delta),
3455
3481
  scale: this.state.viewport.scale
3456
3482
  });
3457
3483
  }
3458
3484
  onEnd() {
3459
- // Nothing to do.
3485
+ if (this.resetSelectedStep) {
3486
+ const distance = this.lastDelta ? this.lastDelta.distance() : 0;
3487
+ if (distance > 2) {
3488
+ return;
3489
+ }
3490
+ this.stateModifier.tryResetSelectedStep();
3491
+ }
3460
3492
  }
3461
3493
  }
3462
3494
 
@@ -3481,7 +3513,7 @@ class SelectStepBehavior {
3481
3513
  if (delta.distance() > 2) {
3482
3514
  const canDrag = !this.state.isReadonly && !this.isDragDisabled;
3483
3515
  if (canDrag) {
3484
- this.state.setSelectedStepId(null);
3516
+ this.stateModifier.tryResetSelectedStep();
3485
3517
  return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
3486
3518
  }
3487
3519
  else {
@@ -3493,9 +3525,12 @@ class SelectStepBehavior {
3493
3525
  if (interrupt) {
3494
3526
  return;
3495
3527
  }
3496
- if (!this.stateModifier.trySelectStep(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3497
- // If we cannot select the step, we clear the selection.
3498
- this.state.setSelectedStepId(null);
3528
+ if (this.stateModifier.isSelectable(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3529
+ this.stateModifier.trySelectStepById(this.pressedStepComponent.step.id);
3530
+ }
3531
+ else {
3532
+ // If the step is not selectable, we try to reset the selection.
3533
+ this.stateModifier.tryResetSelectedStep();
3499
3534
  }
3500
3535
  return new SelectStepBehaviorEndToken(this.pressedStepComponent.step.id, Date.now());
3501
3536
  }
@@ -3730,7 +3765,7 @@ class ContextMenuItemsBuilder {
3730
3765
  label: this.i18n('contextMenu.unselect', 'Unselect'),
3731
3766
  order: 10,
3732
3767
  callback: () => {
3733
- this.state.setSelectedStepId(null);
3768
+ this.stateModifier.tryResetSelectedStep();
3734
3769
  }
3735
3770
  });
3736
3771
  }
@@ -3745,12 +3780,12 @@ class ContextMenuItemsBuilder {
3745
3780
  }
3746
3781
  }
3747
3782
  if (!this.state.isReadonly) {
3748
- if (this.stateModifier.isDeletable(step.id)) {
3783
+ if (this.stateModifier.isDeletable(step, parentSequence)) {
3749
3784
  items.push({
3750
3785
  label: this.i18n('contextMenu.delete', 'Delete'),
3751
3786
  order: 30,
3752
3787
  callback: () => {
3753
- this.stateModifier.tryDelete(step.id);
3788
+ this.stateModifier.tryDeleteById(step.id);
3754
3789
  }
3755
3790
  });
3756
3791
  }
@@ -4090,7 +4125,7 @@ class DesignerView {
4090
4125
 
4091
4126
  const SAFE_OFFSET = 10;
4092
4127
  class DefaultDraggedComponent {
4093
- static create(parent, step, componentContext) {
4128
+ static create(parent, step, _, componentContext) {
4094
4129
  const canvas = Dom.svg('svg');
4095
4130
  canvas.style.marginLeft = -10 + 'px';
4096
4131
  canvas.style.marginTop = -10 + 'px';
@@ -4993,6 +5028,7 @@ class Designer {
4993
5028
  designerContext.state.onViewportChanged.subscribe(designer.onViewportChanged.forward);
4994
5029
  designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward);
4995
5030
  designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward);
5031
+ designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward);
4996
5032
  return designer;
4997
5033
  }
4998
5034
  constructor(view, state, stateModifier, walker, historyController, api) {
@@ -5018,6 +5054,10 @@ class Designer {
5018
5054
  * @description Fires when the selected step has changed.
5019
5055
  */
5020
5056
  this.onSelectedStepIdChanged = new SimpleEvent();
5057
+ /**
5058
+ * @description Fires when the designer could not unselect the currently selected step due to restrictions.
5059
+ */
5060
+ this.onStepUnselectionBlocked = new SimpleEvent();
5021
5061
  /**
5022
5062
  * @description Fires when the toolbox is collapsed or expanded.
5023
5063
  */
@@ -5061,7 +5101,13 @@ class Designer {
5061
5101
  * @description Selects a step by the id.
5062
5102
  */
5063
5103
  selectStepById(stepId) {
5064
- this.stateModifier.trySelectStepById(stepId);
5104
+ this.state.setSelectedStepId(stepId);
5105
+ }
5106
+ /**
5107
+ * @description Unselects the selected step.
5108
+ */
5109
+ clearSelectedStep() {
5110
+ this.state.setSelectedStepId(null);
5065
5111
  }
5066
5112
  /**
5067
5113
  * @returns the current viewport.
@@ -5082,12 +5128,6 @@ class Designer {
5082
5128
  resetViewport() {
5083
5129
  this.api.viewport.resetViewport();
5084
5130
  }
5085
- /**
5086
- * @description Unselects the selected step.
5087
- */
5088
- clearSelectedStep() {
5089
- this.state.setSelectedStepId(null);
5090
- }
5091
5131
  /**
5092
5132
  * @description Moves the viewport to the step with the animation.
5093
5133
  */
package/lib/index.d.ts CHANGED
@@ -107,6 +107,7 @@ declare class DesignerState {
107
107
  isEditorCollapsed: boolean;
108
108
  readonly onViewportChanged: SimpleEvent<Viewport>;
109
109
  readonly onSelectedStepIdChanged: SimpleEvent<string | null>;
110
+ readonly onStepUnselectionBlocked: SimpleEvent<string | null>;
110
111
  readonly onFolderPathChanged: SimpleEvent<string[]>;
111
112
  readonly onIsReadonlyChanged: SimpleEvent<boolean>;
112
113
  readonly onIsDraggingChanged: SimpleEvent<boolean>;
@@ -126,6 +127,7 @@ declare class DesignerState {
126
127
  tryGetLastStepIdFromFolderPath(): string | null;
127
128
  setDefinition(definition: Definition): void;
128
129
  notifyDefinitionChanged(changeType: DefinitionChangeType, stepId: string | null): void;
130
+ notifyStepUnselectionBlocked(stepId: string | null): void;
129
131
  setViewport(viewport: Viewport): void;
130
132
  setIsReadonly(isReadonly: boolean): void;
131
133
  setIsDragging(isDragging: boolean): void;
@@ -910,7 +912,7 @@ interface UiComponent {
910
912
  destroy(): void;
911
913
  }
912
914
  interface DraggedComponentExtension {
913
- create(parentElement: HTMLElement, step: Step, componentContext: ComponentContext): DraggedComponent;
915
+ create(parentElement: HTMLElement, step: Step, isAttached: boolean, componentContext: ComponentContext): DraggedComponent;
914
916
  }
915
917
  interface DraggedComponent {
916
918
  width: number;
@@ -1125,12 +1127,13 @@ interface PreferenceStorage {
1125
1127
  }
1126
1128
  interface StepsConfiguration {
1127
1129
  isSelectable?: (step: Step, parentSequence: Sequence) => boolean;
1128
- canInsertStep?: (step: Step, targetSequence: Sequence, targetIndex: number) => boolean;
1129
1130
  isDraggable?: (step: Step, parentSequence: Sequence) => boolean;
1130
- canMoveStep?: (sourceSequence: Sequence, step: Step, targetSequence: Sequence, targetIndex: number) => boolean;
1131
1131
  isDeletable?: (step: Step, parentSequence: Sequence) => boolean;
1132
- canDeleteStep?: (step: Step, parentSequence: Sequence) => boolean;
1133
1132
  isDuplicable?: (step: Step, parentSequence: Sequence) => boolean;
1133
+ canUnselectStep?: (step: Step, parentSequence: Sequence) => boolean;
1134
+ canInsertStep?: (step: Step, targetSequence: Sequence, targetIndex: number) => boolean;
1135
+ canMoveStep?: (sourceSequence: Sequence, step: Step, targetSequence: Sequence, targetIndex: number) => boolean;
1136
+ canDeleteStep?: (step: Step, parentSequence: Sequence) => boolean;
1134
1137
  /**
1135
1138
  * @description The designer automatically selects the step after it is dropped. If true, the step will not be selected.
1136
1139
  */
@@ -1199,14 +1202,26 @@ declare class StateModifier {
1199
1202
  constructor(definitionWalker: DefinitionWalker, uidGenerator: UidGenerator, state: DesignerState, configuration: StepsConfiguration, dependencies: StateModifierDependency[]);
1200
1203
  addDependency(dependency: StateModifierDependency): void;
1201
1204
  isSelectable(step: Step, parentSequence: Sequence): boolean;
1202
- trySelectStep(step: Step, parentSequence: Sequence): boolean;
1203
- trySelectStepById(stepId: string): void;
1204
- isDeletable(stepId: string): boolean;
1205
- tryDelete(stepId: string): boolean;
1205
+ isSelectableById(stepId: string): boolean;
1206
+ private canUnselectSelectedStep;
1207
+ /**
1208
+ * @description Check the `isSelectable` callback before calling this method.
1209
+ */
1210
+ trySelectStepById(stepIdOrNull: string | null): boolean;
1211
+ tryResetSelectedStep(): void;
1212
+ isDeletable(step: Step, parentSequence: Sequence): boolean;
1213
+ isDeletableById(stepId: string): boolean;
1214
+ /**
1215
+ * @description Check the `isDeletable` callback before calling this method.
1216
+ */
1217
+ tryDeleteById(stepId: string): boolean;
1206
1218
  tryInsert(step: Step, targetSequence: Sequence, targetIndex: number): boolean;
1207
1219
  isDraggable(step: Step, parentSequence: Sequence): boolean;
1208
1220
  tryMove(sourceSequence: Sequence, step: Step, targetSequence: Sequence, targetIndex: number): boolean;
1209
1221
  isDuplicable(step: Step, parentSequence: Sequence): boolean;
1222
+ /**
1223
+ * @description Check the `isDuplicable` callback before calling this method.
1224
+ */
1210
1225
  tryDuplicate(step: Step, parentSequence: Sequence): boolean;
1211
1226
  replaceDefinition(definition: Definition): void;
1212
1227
  updateDependencies(): void;
@@ -1322,6 +1337,10 @@ declare class Designer<TDefinition extends Definition = Definition> {
1322
1337
  * @description Fires when the selected step has changed.
1323
1338
  */
1324
1339
  readonly onSelectedStepIdChanged: SimpleEvent<string | null>;
1340
+ /**
1341
+ * @description Fires when the designer could not unselect the currently selected step due to restrictions.
1342
+ */
1343
+ readonly onStepUnselectionBlocked: SimpleEvent<string | null>;
1325
1344
  /**
1326
1345
  * @description Fires when the toolbox is collapsed or expanded.
1327
1346
  */
@@ -1354,6 +1373,10 @@ declare class Designer<TDefinition extends Definition = Definition> {
1354
1373
  * @description Selects a step by the id.
1355
1374
  */
1356
1375
  selectStepById(stepId: string): void;
1376
+ /**
1377
+ * @description Unselects the selected step.
1378
+ */
1379
+ clearSelectedStep(): void;
1357
1380
  /**
1358
1381
  * @returns the current viewport.
1359
1382
  */
@@ -1367,10 +1390,6 @@ declare class Designer<TDefinition extends Definition = Definition> {
1367
1390
  * @description Resets the viewport.
1368
1391
  */
1369
1392
  resetViewport(): void;
1370
- /**
1371
- * @description Unselects the selected step.
1372
- */
1373
- clearSelectedStep(): void;
1374
1393
  /**
1375
1394
  * @description Moves the viewport to the step with the animation.
1376
1395
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sequential-workflow-designer",
3
3
  "description": "Customizable no-code component for building flow-based programming applications.",
4
- "version": "0.31.0",
4
+ "version": "0.33.0",
5
5
  "type": "module",
6
6
  "main": "./lib/esm/index.js",
7
7
  "types": "./lib/index.d.ts",