sequential-workflow-designer 0.32.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.32.0/css/designer.css" rel="stylesheet">
110
- <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.32.0/css/designer-light.css" rel="stylesheet">
111
- <link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.32.0/css/designer-dark.css" rel="stylesheet">
112
- <script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.32.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
 
@@ -3097,30 +3096,56 @@
3097
3096
  isSelectable(step, parentSequence) {
3098
3097
  return this.configuration.isSelectable ? this.configuration.isSelectable(step, parentSequence) : true;
3099
3098
  }
3100
- trySelectStep(step, parentSequence) {
3101
- if (this.isSelectable(step, parentSequence)) {
3102
- 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
+ }
3103
3112
  return true;
3104
3113
  }
3105
- return false;
3114
+ return null;
3106
3115
  }
3107
- trySelectStepById(stepId) {
3108
- if (this.configuration.isSelectable) {
3109
- const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3110
- 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;
3111
3124
  }
3112
- else {
3113
- 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;
3114
3132
  }
3133
+ this.trySelectStepById(stepIdOrNull);
3115
3134
  }
3116
- isDeletable(stepId) {
3135
+ isDeletable(step, parentSequence) {
3136
+ return this.configuration.isDeletable ? this.configuration.isDeletable(step, parentSequence) : true;
3137
+ }
3138
+ isDeletableById(stepId) {
3117
3139
  if (this.configuration.isDeletable) {
3118
3140
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3119
3141
  return this.configuration.isDeletable(result.step, result.parentSequence);
3120
3142
  }
3121
3143
  return true;
3122
3144
  }
3123
- tryDelete(stepId) {
3145
+ /**
3146
+ * @description Check the `isDeletable` callback before calling this method.
3147
+ */
3148
+ tryDeleteById(stepId) {
3124
3149
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
3125
3150
  const canDeleteStep = this.configuration.canDeleteStep
3126
3151
  ? this.configuration.canDeleteStep(result.step, result.parentSequence)
@@ -3140,7 +3165,7 @@
3140
3165
  }
3141
3166
  SequenceModifier.insertStep(step, targetSequence, targetIndex);
3142
3167
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepInserted, step.id);
3143
- if (!this.configuration.isAutoSelectDisabled) {
3168
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3144
3169
  this.trySelectStepById(step.id);
3145
3170
  }
3146
3171
  return true;
@@ -3161,14 +3186,17 @@
3161
3186
  }
3162
3187
  apply();
3163
3188
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepMoved, step.id);
3164
- if (!this.configuration.isAutoSelectDisabled) {
3165
- this.trySelectStep(step, targetSequence);
3189
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3190
+ this.trySelectStepById(step.id);
3166
3191
  }
3167
3192
  return true;
3168
3193
  }
3169
3194
  isDuplicable(step, parentSequence) {
3170
3195
  return this.configuration.isDuplicable ? this.configuration.isDuplicable(step, parentSequence) : false;
3171
3196
  }
3197
+ /**
3198
+ * @description Check the `isDuplicable` callback before calling this method.
3199
+ */
3172
3200
  tryDuplicate(step, parentSequence) {
3173
3201
  const duplicator = new StepDuplicator(this.uidGenerator, this.definitionWalker);
3174
3202
  const index = parentSequence.indexOf(step);
@@ -3195,6 +3223,7 @@
3195
3223
  this.isEditorCollapsed = isEditorCollapsed;
3196
3224
  this.onViewportChanged = new SimpleEvent();
3197
3225
  this.onSelectedStepIdChanged = new SimpleEvent();
3226
+ this.onStepUnselectionBlocked = new SimpleEvent();
3198
3227
  this.onFolderPathChanged = new SimpleEvent();
3199
3228
  this.onIsReadonlyChanged = new SimpleEvent();
3200
3229
  this.onIsDraggingChanged = new SimpleEvent();
@@ -3235,6 +3264,9 @@
3235
3264
  notifyDefinitionChanged(changeType, stepId) {
3236
3265
  this.onDefinitionChanged.forward({ changeType, stepId });
3237
3266
  }
3267
+ notifyStepUnselectionBlocked(stepId) {
3268
+ this.onStepUnselectionBlocked.forward(stepId);
3269
+ }
3238
3270
  setViewport(viewport) {
3239
3271
  this.viewport = viewport;
3240
3272
  this.onViewportChanged.forward(viewport);
@@ -3626,24 +3658,23 @@
3626
3658
  this.stateModifier = stateModifier;
3627
3659
  }
3628
3660
  onStart() {
3629
- if (this.resetSelectedStep) {
3630
- const stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
3631
- if (stepIdOrNull) {
3632
- this.stateModifier.trySelectStepById(stepIdOrNull);
3633
- }
3634
- else {
3635
- this.state.setSelectedStepId(null);
3636
- }
3637
- }
3661
+ // Nothing to do.
3638
3662
  }
3639
3663
  onMove(delta) {
3664
+ this.lastDelta = delta;
3640
3665
  this.state.setViewport({
3641
3666
  position: this.startPosition.subtract(delta),
3642
3667
  scale: this.state.viewport.scale
3643
3668
  });
3644
3669
  }
3645
3670
  onEnd() {
3646
- // 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
+ }
3647
3678
  }
3648
3679
  }
3649
3680
 
@@ -3668,7 +3699,7 @@
3668
3699
  if (delta.distance() > 2) {
3669
3700
  const canDrag = !this.state.isReadonly && !this.isDragDisabled;
3670
3701
  if (canDrag) {
3671
- this.state.setSelectedStepId(null);
3702
+ this.stateModifier.tryResetSelectedStep();
3672
3703
  return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
3673
3704
  }
3674
3705
  else {
@@ -3680,9 +3711,12 @@
3680
3711
  if (interrupt) {
3681
3712
  return;
3682
3713
  }
3683
- if (!this.stateModifier.trySelectStep(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3684
- // If we cannot select the step, we clear the selection.
3685
- 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();
3686
3720
  }
3687
3721
  return new SelectStepBehaviorEndToken(this.pressedStepComponent.step.id, Date.now());
3688
3722
  }
@@ -3917,7 +3951,7 @@
3917
3951
  label: this.i18n('contextMenu.unselect', 'Unselect'),
3918
3952
  order: 10,
3919
3953
  callback: () => {
3920
- this.state.setSelectedStepId(null);
3954
+ this.stateModifier.tryResetSelectedStep();
3921
3955
  }
3922
3956
  });
3923
3957
  }
@@ -3932,12 +3966,12 @@
3932
3966
  }
3933
3967
  }
3934
3968
  if (!this.state.isReadonly) {
3935
- if (this.stateModifier.isDeletable(step.id)) {
3969
+ if (this.stateModifier.isDeletable(step, parentSequence)) {
3936
3970
  items.push({
3937
3971
  label: this.i18n('contextMenu.delete', 'Delete'),
3938
3972
  order: 30,
3939
3973
  callback: () => {
3940
- this.stateModifier.tryDelete(step.id);
3974
+ this.stateModifier.tryDeleteById(step.id);
3941
3975
  }
3942
3976
  });
3943
3977
  }
@@ -5180,6 +5214,7 @@
5180
5214
  designerContext.state.onViewportChanged.subscribe(designer.onViewportChanged.forward);
5181
5215
  designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward);
5182
5216
  designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward);
5217
+ designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward);
5183
5218
  return designer;
5184
5219
  }
5185
5220
  constructor(view, state, stateModifier, walker, historyController, api) {
@@ -5205,6 +5240,10 @@
5205
5240
  * @description Fires when the selected step has changed.
5206
5241
  */
5207
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();
5208
5247
  /**
5209
5248
  * @description Fires when the toolbox is collapsed or expanded.
5210
5249
  */
@@ -5248,7 +5287,13 @@
5248
5287
  * @description Selects a step by the id.
5249
5288
  */
5250
5289
  selectStepById(stepId) {
5251
- 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);
5252
5297
  }
5253
5298
  /**
5254
5299
  * @returns the current viewport.
@@ -5269,12 +5314,6 @@
5269
5314
  resetViewport() {
5270
5315
  this.api.viewport.resetViewport();
5271
5316
  }
5272
- /**
5273
- * @description Unselects the selected step.
5274
- */
5275
- clearSelectedStep() {
5276
- this.state.setSelectedStepId(null);
5277
- }
5278
5317
  /**
5279
5318
  * @description Moves the viewport to the step with the animation.
5280
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
 
@@ -2912,30 +2911,56 @@ class StateModifier {
2912
2911
  isSelectable(step, parentSequence) {
2913
2912
  return this.configuration.isSelectable ? this.configuration.isSelectable(step, parentSequence) : true;
2914
2913
  }
2915
- trySelectStep(step, parentSequence) {
2916
- if (this.isSelectable(step, parentSequence)) {
2917
- 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
+ }
2918
2927
  return true;
2919
2928
  }
2920
- return false;
2929
+ return null;
2921
2930
  }
2922
- trySelectStepById(stepId) {
2923
- if (this.configuration.isSelectable) {
2924
- const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2925
- 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;
2926
2939
  }
2927
- else {
2928
- 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;
2929
2947
  }
2948
+ this.trySelectStepById(stepIdOrNull);
2930
2949
  }
2931
- isDeletable(stepId) {
2950
+ isDeletable(step, parentSequence) {
2951
+ return this.configuration.isDeletable ? this.configuration.isDeletable(step, parentSequence) : true;
2952
+ }
2953
+ isDeletableById(stepId) {
2932
2954
  if (this.configuration.isDeletable) {
2933
2955
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2934
2956
  return this.configuration.isDeletable(result.step, result.parentSequence);
2935
2957
  }
2936
2958
  return true;
2937
2959
  }
2938
- tryDelete(stepId) {
2960
+ /**
2961
+ * @description Check the `isDeletable` callback before calling this method.
2962
+ */
2963
+ tryDeleteById(stepId) {
2939
2964
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2940
2965
  const canDeleteStep = this.configuration.canDeleteStep
2941
2966
  ? this.configuration.canDeleteStep(result.step, result.parentSequence)
@@ -2955,7 +2980,7 @@ class StateModifier {
2955
2980
  }
2956
2981
  SequenceModifier.insertStep(step, targetSequence, targetIndex);
2957
2982
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepInserted, step.id);
2958
- if (!this.configuration.isAutoSelectDisabled) {
2983
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
2959
2984
  this.trySelectStepById(step.id);
2960
2985
  }
2961
2986
  return true;
@@ -2976,14 +3001,17 @@ class StateModifier {
2976
3001
  }
2977
3002
  apply();
2978
3003
  this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepMoved, step.id);
2979
- if (!this.configuration.isAutoSelectDisabled) {
2980
- this.trySelectStep(step, targetSequence);
3004
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3005
+ this.trySelectStepById(step.id);
2981
3006
  }
2982
3007
  return true;
2983
3008
  }
2984
3009
  isDuplicable(step, parentSequence) {
2985
3010
  return this.configuration.isDuplicable ? this.configuration.isDuplicable(step, parentSequence) : false;
2986
3011
  }
3012
+ /**
3013
+ * @description Check the `isDuplicable` callback before calling this method.
3014
+ */
2987
3015
  tryDuplicate(step, parentSequence) {
2988
3016
  const duplicator = new StepDuplicator(this.uidGenerator, this.definitionWalker);
2989
3017
  const index = parentSequence.indexOf(step);
@@ -3010,6 +3038,7 @@ class DesignerState {
3010
3038
  this.isEditorCollapsed = isEditorCollapsed;
3011
3039
  this.onViewportChanged = new SimpleEvent();
3012
3040
  this.onSelectedStepIdChanged = new SimpleEvent();
3041
+ this.onStepUnselectionBlocked = new SimpleEvent();
3013
3042
  this.onFolderPathChanged = new SimpleEvent();
3014
3043
  this.onIsReadonlyChanged = new SimpleEvent();
3015
3044
  this.onIsDraggingChanged = new SimpleEvent();
@@ -3050,6 +3079,9 @@ class DesignerState {
3050
3079
  notifyDefinitionChanged(changeType, stepId) {
3051
3080
  this.onDefinitionChanged.forward({ changeType, stepId });
3052
3081
  }
3082
+ notifyStepUnselectionBlocked(stepId) {
3083
+ this.onStepUnselectionBlocked.forward(stepId);
3084
+ }
3053
3085
  setViewport(viewport) {
3054
3086
  this.viewport = viewport;
3055
3087
  this.onViewportChanged.forward(viewport);
@@ -3441,24 +3473,23 @@ class MoveViewportBehavior {
3441
3473
  this.stateModifier = stateModifier;
3442
3474
  }
3443
3475
  onStart() {
3444
- if (this.resetSelectedStep) {
3445
- const stepIdOrNull = this.state.tryGetLastStepIdFromFolderPath();
3446
- if (stepIdOrNull) {
3447
- this.stateModifier.trySelectStepById(stepIdOrNull);
3448
- }
3449
- else {
3450
- this.state.setSelectedStepId(null);
3451
- }
3452
- }
3476
+ // Nothing to do.
3453
3477
  }
3454
3478
  onMove(delta) {
3479
+ this.lastDelta = delta;
3455
3480
  this.state.setViewport({
3456
3481
  position: this.startPosition.subtract(delta),
3457
3482
  scale: this.state.viewport.scale
3458
3483
  });
3459
3484
  }
3460
3485
  onEnd() {
3461
- // 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
+ }
3462
3493
  }
3463
3494
  }
3464
3495
 
@@ -3483,7 +3514,7 @@ class SelectStepBehavior {
3483
3514
  if (delta.distance() > 2) {
3484
3515
  const canDrag = !this.state.isReadonly && !this.isDragDisabled;
3485
3516
  if (canDrag) {
3486
- this.state.setSelectedStepId(null);
3517
+ this.stateModifier.tryResetSelectedStep();
3487
3518
  return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
3488
3519
  }
3489
3520
  else {
@@ -3495,9 +3526,12 @@ class SelectStepBehavior {
3495
3526
  if (interrupt) {
3496
3527
  return;
3497
3528
  }
3498
- if (!this.stateModifier.trySelectStep(this.pressedStepComponent.step, this.pressedStepComponent.parentSequence)) {
3499
- // If we cannot select the step, we clear the selection.
3500
- 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();
3501
3535
  }
3502
3536
  return new SelectStepBehaviorEndToken(this.pressedStepComponent.step.id, Date.now());
3503
3537
  }
@@ -3732,7 +3766,7 @@ class ContextMenuItemsBuilder {
3732
3766
  label: this.i18n('contextMenu.unselect', 'Unselect'),
3733
3767
  order: 10,
3734
3768
  callback: () => {
3735
- this.state.setSelectedStepId(null);
3769
+ this.stateModifier.tryResetSelectedStep();
3736
3770
  }
3737
3771
  });
3738
3772
  }
@@ -3747,12 +3781,12 @@ class ContextMenuItemsBuilder {
3747
3781
  }
3748
3782
  }
3749
3783
  if (!this.state.isReadonly) {
3750
- if (this.stateModifier.isDeletable(step.id)) {
3784
+ if (this.stateModifier.isDeletable(step, parentSequence)) {
3751
3785
  items.push({
3752
3786
  label: this.i18n('contextMenu.delete', 'Delete'),
3753
3787
  order: 30,
3754
3788
  callback: () => {
3755
- this.stateModifier.tryDelete(step.id);
3789
+ this.stateModifier.tryDeleteById(step.id);
3756
3790
  }
3757
3791
  });
3758
3792
  }
@@ -4995,6 +5029,7 @@ class Designer {
4995
5029
  designerContext.state.onViewportChanged.subscribe(designer.onViewportChanged.forward);
4996
5030
  designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward);
4997
5031
  designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward);
5032
+ designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward);
4998
5033
  return designer;
4999
5034
  }
5000
5035
  constructor(view, state, stateModifier, walker, historyController, api) {
@@ -5020,6 +5055,10 @@ class Designer {
5020
5055
  * @description Fires when the selected step has changed.
5021
5056
  */
5022
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();
5023
5062
  /**
5024
5063
  * @description Fires when the toolbox is collapsed or expanded.
5025
5064
  */
@@ -5063,7 +5102,13 @@ class Designer {
5063
5102
  * @description Selects a step by the id.
5064
5103
  */
5065
5104
  selectStepById(stepId) {
5066
- 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);
5067
5112
  }
5068
5113
  /**
5069
5114
  * @returns the current viewport.
@@ -5084,12 +5129,6 @@ class Designer {
5084
5129
  resetViewport() {
5085
5130
  this.api.viewport.resetViewport();
5086
5131
  }
5087
- /**
5088
- * @description Unselects the selected step.
5089
- */
5090
- clearSelectedStep() {
5091
- this.state.setSelectedStepId(null);
5092
- }
5093
5132
  /**
5094
5133
  * @description Moves the viewport to the step with the animation.
5095
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
 
@@ -2911,30 +2910,56 @@ class StateModifier {
2911
2910
  isSelectable(step, parentSequence) {
2912
2911
  return this.configuration.isSelectable ? this.configuration.isSelectable(step, parentSequence) : true;
2913
2912
  }
2914
- trySelectStep(step, parentSequence) {
2915
- if (this.isSelectable(step, parentSequence)) {
2916
- 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
+ }
2917
2926
  return true;
2918
2927
  }
2919
- return false;
2928
+ return null;
2920
2929
  }
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);
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;
2925
2938
  }
2926
- else {
2927
- 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;
2928
2946
  }
2947
+ this.trySelectStepById(stepIdOrNull);
2929
2948
  }
2930
- isDeletable(stepId) {
2949
+ isDeletable(step, parentSequence) {
2950
+ return this.configuration.isDeletable ? this.configuration.isDeletable(step, parentSequence) : true;
2951
+ }
2952
+ isDeletableById(stepId) {
2931
2953
  if (this.configuration.isDeletable) {
2932
2954
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2933
2955
  return this.configuration.isDeletable(result.step, result.parentSequence);
2934
2956
  }
2935
2957
  return true;
2936
2958
  }
2937
- tryDelete(stepId) {
2959
+ /**
2960
+ * @description Check the `isDeletable` callback before calling this method.
2961
+ */
2962
+ tryDeleteById(stepId) {
2938
2963
  const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2939
2964
  const canDeleteStep = this.configuration.canDeleteStep
2940
2965
  ? this.configuration.canDeleteStep(result.step, result.parentSequence)
@@ -2954,7 +2979,7 @@ class StateModifier {
2954
2979
  }
2955
2980
  SequenceModifier.insertStep(step, targetSequence, targetIndex);
2956
2981
  this.state.notifyDefinitionChanged(DefinitionChangeType.stepInserted, step.id);
2957
- if (!this.configuration.isAutoSelectDisabled) {
2982
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
2958
2983
  this.trySelectStepById(step.id);
2959
2984
  }
2960
2985
  return true;
@@ -2975,14 +3000,17 @@ class StateModifier {
2975
3000
  }
2976
3001
  apply();
2977
3002
  this.state.notifyDefinitionChanged(DefinitionChangeType.stepMoved, step.id);
2978
- if (!this.configuration.isAutoSelectDisabled) {
2979
- this.trySelectStep(step, targetSequence);
3003
+ if (!this.configuration.isAutoSelectDisabled && this.isSelectable(step, targetSequence)) {
3004
+ this.trySelectStepById(step.id);
2980
3005
  }
2981
3006
  return true;
2982
3007
  }
2983
3008
  isDuplicable(step, parentSequence) {
2984
3009
  return this.configuration.isDuplicable ? this.configuration.isDuplicable(step, parentSequence) : false;
2985
3010
  }
3011
+ /**
3012
+ * @description Check the `isDuplicable` callback before calling this method.
3013
+ */
2986
3014
  tryDuplicate(step, parentSequence) {
2987
3015
  const duplicator = new StepDuplicator(this.uidGenerator, this.definitionWalker);
2988
3016
  const index = parentSequence.indexOf(step);
@@ -3009,6 +3037,7 @@ class DesignerState {
3009
3037
  this.isEditorCollapsed = isEditorCollapsed;
3010
3038
  this.onViewportChanged = new SimpleEvent();
3011
3039
  this.onSelectedStepIdChanged = new SimpleEvent();
3040
+ this.onStepUnselectionBlocked = new SimpleEvent();
3012
3041
  this.onFolderPathChanged = new SimpleEvent();
3013
3042
  this.onIsReadonlyChanged = new SimpleEvent();
3014
3043
  this.onIsDraggingChanged = new SimpleEvent();
@@ -3049,6 +3078,9 @@ class DesignerState {
3049
3078
  notifyDefinitionChanged(changeType, stepId) {
3050
3079
  this.onDefinitionChanged.forward({ changeType, stepId });
3051
3080
  }
3081
+ notifyStepUnselectionBlocked(stepId) {
3082
+ this.onStepUnselectionBlocked.forward(stepId);
3083
+ }
3052
3084
  setViewport(viewport) {
3053
3085
  this.viewport = viewport;
3054
3086
  this.onViewportChanged.forward(viewport);
@@ -3440,24 +3472,23 @@ class MoveViewportBehavior {
3440
3472
  this.stateModifier = stateModifier;
3441
3473
  }
3442
3474
  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
- }
3475
+ // Nothing to do.
3452
3476
  }
3453
3477
  onMove(delta) {
3478
+ this.lastDelta = delta;
3454
3479
  this.state.setViewport({
3455
3480
  position: this.startPosition.subtract(delta),
3456
3481
  scale: this.state.viewport.scale
3457
3482
  });
3458
3483
  }
3459
3484
  onEnd() {
3460
- // 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
+ }
3461
3492
  }
3462
3493
  }
3463
3494
 
@@ -3482,7 +3513,7 @@ class SelectStepBehavior {
3482
3513
  if (delta.distance() > 2) {
3483
3514
  const canDrag = !this.state.isReadonly && !this.isDragDisabled;
3484
3515
  if (canDrag) {
3485
- this.state.setSelectedStepId(null);
3516
+ this.stateModifier.tryResetSelectedStep();
3486
3517
  return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
3487
3518
  }
3488
3519
  else {
@@ -3494,9 +3525,12 @@ class SelectStepBehavior {
3494
3525
  if (interrupt) {
3495
3526
  return;
3496
3527
  }
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);
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();
3500
3534
  }
3501
3535
  return new SelectStepBehaviorEndToken(this.pressedStepComponent.step.id, Date.now());
3502
3536
  }
@@ -3731,7 +3765,7 @@ class ContextMenuItemsBuilder {
3731
3765
  label: this.i18n('contextMenu.unselect', 'Unselect'),
3732
3766
  order: 10,
3733
3767
  callback: () => {
3734
- this.state.setSelectedStepId(null);
3768
+ this.stateModifier.tryResetSelectedStep();
3735
3769
  }
3736
3770
  });
3737
3771
  }
@@ -3746,12 +3780,12 @@ class ContextMenuItemsBuilder {
3746
3780
  }
3747
3781
  }
3748
3782
  if (!this.state.isReadonly) {
3749
- if (this.stateModifier.isDeletable(step.id)) {
3783
+ if (this.stateModifier.isDeletable(step, parentSequence)) {
3750
3784
  items.push({
3751
3785
  label: this.i18n('contextMenu.delete', 'Delete'),
3752
3786
  order: 30,
3753
3787
  callback: () => {
3754
- this.stateModifier.tryDelete(step.id);
3788
+ this.stateModifier.tryDeleteById(step.id);
3755
3789
  }
3756
3790
  });
3757
3791
  }
@@ -4994,6 +5028,7 @@ class Designer {
4994
5028
  designerContext.state.onViewportChanged.subscribe(designer.onViewportChanged.forward);
4995
5029
  designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward);
4996
5030
  designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward);
5031
+ designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward);
4997
5032
  return designer;
4998
5033
  }
4999
5034
  constructor(view, state, stateModifier, walker, historyController, api) {
@@ -5019,6 +5054,10 @@ class Designer {
5019
5054
  * @description Fires when the selected step has changed.
5020
5055
  */
5021
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();
5022
5061
  /**
5023
5062
  * @description Fires when the toolbox is collapsed or expanded.
5024
5063
  */
@@ -5062,7 +5101,13 @@ class Designer {
5062
5101
  * @description Selects a step by the id.
5063
5102
  */
5064
5103
  selectStepById(stepId) {
5065
- 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);
5066
5111
  }
5067
5112
  /**
5068
5113
  * @returns the current viewport.
@@ -5083,12 +5128,6 @@ class Designer {
5083
5128
  resetViewport() {
5084
5129
  this.api.viewport.resetViewport();
5085
5130
  }
5086
- /**
5087
- * @description Unselects the selected step.
5088
- */
5089
- clearSelectedStep() {
5090
- this.state.setSelectedStepId(null);
5091
- }
5092
5131
  /**
5093
5132
  * @description Moves the viewport to the step with the animation.
5094
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;
@@ -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.32.0",
4
+ "version": "0.33.0",
5
5
  "type": "module",
6
6
  "main": "./lib/esm/index.js",
7
7
  "types": "./lib/index.d.ts",