@vectoriox/iox-builder 1.4.4 → 1.4.5

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.
@@ -3823,7 +3823,6 @@ class BuilderRepeaterComponent {
3823
3823
  }
3824
3824
  ngOnInit() {
3825
3825
  this.orgId = this.activatedRoute.snapshot.paramMap.get('orgId') || 'default';
3826
- // When a binding is added/removed on any node, regenerate the preview rows.
3827
3826
  this.bindingSub = this.panelEventService.subscribe(event => {
3828
3827
  if (event.type !== PanelEventTypes.BINDING_CHANGED)
3829
3828
  return;
@@ -3901,32 +3900,54 @@ class BuilderRepeaterComponent {
3901
3900
  }
3902
3901
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: BuilderRepeaterComponent, deps: [{ token: DragEngineService }, { token: OverlayService }, { token: IOX_CONTENT_SERVICE, optional: true }, { token: DataSourceRegistryService }, { token: PanelEventService }, { token: i5.ActivatedRoute }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3903
3902
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: BuilderRepeaterComponent, isStandalone: false, selector: "app-builder-repeater", inputs: { children: "children", style: "style", nodeId: "nodeId", dropListId: "dropListId", source: "source", limit: "limit" }, outputs: { childClick: "childClick", childMouseEnter: "childMouseEnter", childMouseLeave: "childMouseLeave" }, ngImport: i0, template: `
3904
- <div class="repeater-root" [ngClass]="['iox-node-' + nodeId, children.length ? 'has-children' : '']">
3903
+ <ng-template #badgeContent>
3904
+ <i class="ph-thin ph-repeat"></i>
3905
+ <span *ngIf="source">{{ source }}</span>
3906
+ <span *ngIf="!source" class="repeater-badge-empty">No source</span>
3907
+ <span *ngIf="items.length" class="repeater-badge-count">&times; {{ items.length }}</span>
3908
+ <span *ngIf="isLoading" class="repeater-badge-loading"><i class="ph-thin ph-circle-notch"></i></span>
3909
+ </ng-template>
3905
3910
 
3906
- <!-- Badge: always visible when empty, absolute hover-only when has children -->
3907
- <div class="repeater-badge">
3908
- <i class="ph-thin ph-repeat"></i>
3909
- <span *ngIf="source">{{ source }}</span>
3910
- <span *ngIf="!source" class="repeater-badge-empty">No source</span>
3911
- <span *ngIf="items.length" class="repeater-badge-count">&times; {{ items.length }}</span>
3912
- <span *ngIf="isLoading" class="repeater-badge-loading"><i class="ph-thin ph-circle-notch"></i></span>
3911
+ <!--
3912
+ .repeater-wrapper is the layout root.
3913
+ In has-children state, .repeater-badge lives here as a direct child
3914
+ (position:absolute, hover-only) so it is NOT a child of .repeater-root
3915
+ and does NOT shift the :nth-child index of the item wrappers.
3916
+
3917
+ In empty state, .repeater-badge lives inside .repeater-root (no items
3918
+ to count, so :nth-child is irrelevant there).
3919
+ -->
3920
+ <div class="repeater-wrapper" [class.has-children]="children.length > 0">
3921
+
3922
+ <!-- HAS-CHILDREN: badge outside root, absolute over wrapper -->
3923
+ <div *ngIf="children.length > 0" class="repeater-badge">
3924
+ <ng-container *ngTemplateOutlet="badgeContent"></ng-container>
3913
3925
  </div>
3914
3926
 
3915
- <!-- Template drop zone — user designs one item here -->
3916
- <div class="repeater-template"
3927
+ <div class="repeater-root"
3928
+ [ngClass]="['iox-node-' + nodeId]"
3917
3929
  ioxDropzone
3918
3930
  [ioxDropzoneId]="dropListId"
3919
3931
  [ioxDropzoneData]="children"
3920
3932
  [ioxDropzonePostDrop]="refreshPreviewsBound"
3921
3933
  (ioxDrop)="onDrop($event)">
3922
3934
 
3923
- <div *ngIf="!children.length" class="repeater-placeholder">
3924
- <i class="ph-thin ph-rows"></i>
3925
- <span>Drop a component here as the item template</span>
3926
- </div>
3935
+ <!-- EMPTY STATE: badge + placeholder inside root -->
3936
+ <ng-container *ngIf="!children.length">
3937
+ <div class="repeater-badge">
3938
+ <ng-container *ngTemplateOutlet="badgeContent"></ng-container>
3939
+ </div>
3940
+ <div class="repeater-placeholder">
3941
+ <i class="ph-thin ph-rows"></i>
3942
+ <span>Drop a component here as the item template</span>
3943
+ </div>
3944
+ </ng-container>
3927
3945
 
3946
+ <!-- Template items — DIRECT children of repeater-root.
3947
+ :first-child / :nth-child(odd) etc. now correctly target these
3948
+ as siblings of the preview items below. -->
3928
3949
  <div *ngFor="let child of children"
3929
- [ngClass]="['repeater-template-child', 'iox-outer-' + (child.styleId ?? child.id)]"
3950
+ [ngClass]="['repeater-item-template', 'iox-outer-' + (child.styleId ?? child.id)]"
3930
3951
  ioxDraggable
3931
3952
  [ioxDragData]="child"
3932
3953
  [ioxDragSourceId]="dropListId">
@@ -3937,54 +3958,74 @@ class BuilderRepeaterComponent {
3937
3958
  (onMouseLeave)="childMouseLeave.emit()">
3938
3959
  </ng-container>
3939
3960
  </div>
3940
- </div>
3941
3961
 
3942
- <!-- Preview items for rows 2..N one iox-outer wrapper per child so
3943
- width/margin outer props apply, and items participate directly in
3944
- the repeater-root grid/flex (template uses display:contents). -->
3945
- <ng-container *ngFor="let row of previewRows">
3946
- <div *ngFor="let child of row"
3947
- [ngClass]="['repeater-preview-child', 'iox-outer-' + (child.styleId ?? child.id)]">
3948
- <ng-container
3949
- [ioxRender]="child"
3950
- (onClick)="$event"
3951
- (onMouseEnter)="$event"
3952
- (onMouseLeave)="undefined">
3953
- </ng-container>
3954
- </div>
3955
- </ng-container>
3962
+ <!-- Preview items also DIRECT children of repeater-root. -->
3963
+ <ng-container *ngFor="let row of previewRows">
3964
+ <div *ngFor="let child of row"
3965
+ [ngClass]="['repeater-preview-child', 'iox-outer-' + (child.styleId ?? child.id)]">
3966
+ <ng-container
3967
+ [ioxRender]="child"
3968
+ (onClick)="$event"
3969
+ (onMouseEnter)="$event"
3970
+ (onMouseLeave)="undefined">
3971
+ </ng-container>
3972
+ </div>
3973
+ </ng-container>
3974
+ </div>
3956
3975
  </div>
3957
- `, isInline: true, styles: [".repeater-root{position:relative;box-sizing:border-box}.repeater-badge{display:flex;align-items:center;gap:.4rem;padding:4px 8px;font-size:11px;color:#cb9090;background:#cb909014;border:1px dashed rgba(203,144,144,.4);border-bottom:none;border-radius:4px 4px 0 0;-webkit-user-select:none;user-select:none}.repeater-root.has-children .repeater-badge{position:absolute;top:0;left:0;z-index:10;border-radius:0 0 4px;border:1px solid rgba(203,144,144,.5);opacity:0;cursor:pointer;transition:opacity .15s}.repeater-root.has-children:hover .repeater-badge{opacity:1}.repeater-root.has-children .repeater-template{border:none;border-radius:0;padding:0;min-height:unset;display:contents}.repeater-badge i{font-size:13px}.repeater-badge-empty{opacity:.55}.repeater-badge-count{margin-left:auto;font-weight:600}.repeater-badge-loading i{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.repeater-template{border:1px dashed rgba(203,144,144,.4);border-radius:0 0 4px 4px;padding:4px;min-height:40px}.repeater-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1.5rem 1rem;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none}.repeater-placeholder i{font-size:20px}.repeater-template-child{min-width:0}.repeater-preview-child{opacity:.55;pointer-events:none;min-width:0}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: RenderDirective, selector: "[ioxRender]", inputs: ["ioxRender"], outputs: ["onClick", "onMouseEnter", "onMouseLeave"] }, { kind: "directive", type: IoxDraggableDirective, selector: "[ioxDraggable]", inputs: ["ioxDragData", "ioxDragSourceId"] }, { kind: "directive", type: IoxDropzoneDirective, selector: "[ioxDropzone]", inputs: ["ioxDropzoneId", "ioxDropzoneData", "ioxDropzonePostDrop"], outputs: ["ioxDrop"] }] }); }
3976
+ `, isInline: true, styles: [".repeater-wrapper{position:relative;box-sizing:border-box}.repeater-badge{display:flex;align-items:center;gap:.4rem;padding:4px 8px;font-size:11px;color:#cb9090;background:#cb909014;border:1px dashed rgba(203,144,144,.4);border-bottom:none;border-radius:4px 4px 0 0;-webkit-user-select:none;user-select:none}.repeater-wrapper.has-children>.repeater-badge{position:absolute;top:0;left:0;z-index:10;border-radius:0 0 4px;border:1px solid rgba(203,144,144,.5);opacity:0;cursor:pointer;transition:opacity .15s}.repeater-wrapper.has-children:hover>.repeater-badge{opacity:1}.repeater-badge i{font-size:13px}.repeater-badge-empty{opacity:.55}.repeater-badge-count{margin-left:auto;font-weight:600}.repeater-badge-loading i{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.repeater-root{box-sizing:border-box}.repeater-wrapper:not(.has-children) .repeater-root{border:1px dashed rgba(203,144,144,.4);border-top:none;border-radius:0 0 4px 4px;min-height:40px}.repeater-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1.5rem 1rem;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none}.repeater-placeholder i{font-size:20px}.repeater-item-template{min-width:0}.repeater-preview-child{opacity:.55;pointer-events:none;min-width:0}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RenderDirective, selector: "[ioxRender]", inputs: ["ioxRender"], outputs: ["onClick", "onMouseEnter", "onMouseLeave"] }, { kind: "directive", type: IoxDraggableDirective, selector: "[ioxDraggable]", inputs: ["ioxDragData", "ioxDragSourceId"] }, { kind: "directive", type: IoxDropzoneDirective, selector: "[ioxDropzone]", inputs: ["ioxDropzoneId", "ioxDropzoneData", "ioxDropzonePostDrop"], outputs: ["ioxDrop"] }] }); }
3958
3977
  }
3959
3978
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: BuilderRepeaterComponent, decorators: [{
3960
3979
  type: Component,
3961
3980
  args: [{ selector: 'app-builder-repeater', template: `
3962
- <div class="repeater-root" [ngClass]="['iox-node-' + nodeId, children.length ? 'has-children' : '']">
3981
+ <ng-template #badgeContent>
3982
+ <i class="ph-thin ph-repeat"></i>
3983
+ <span *ngIf="source">{{ source }}</span>
3984
+ <span *ngIf="!source" class="repeater-badge-empty">No source</span>
3985
+ <span *ngIf="items.length" class="repeater-badge-count">&times; {{ items.length }}</span>
3986
+ <span *ngIf="isLoading" class="repeater-badge-loading"><i class="ph-thin ph-circle-notch"></i></span>
3987
+ </ng-template>
3963
3988
 
3964
- <!-- Badge: always visible when empty, absolute hover-only when has children -->
3965
- <div class="repeater-badge">
3966
- <i class="ph-thin ph-repeat"></i>
3967
- <span *ngIf="source">{{ source }}</span>
3968
- <span *ngIf="!source" class="repeater-badge-empty">No source</span>
3969
- <span *ngIf="items.length" class="repeater-badge-count">&times; {{ items.length }}</span>
3970
- <span *ngIf="isLoading" class="repeater-badge-loading"><i class="ph-thin ph-circle-notch"></i></span>
3989
+ <!--
3990
+ .repeater-wrapper is the layout root.
3991
+ In has-children state, .repeater-badge lives here as a direct child
3992
+ (position:absolute, hover-only) so it is NOT a child of .repeater-root
3993
+ and does NOT shift the :nth-child index of the item wrappers.
3994
+
3995
+ In empty state, .repeater-badge lives inside .repeater-root (no items
3996
+ to count, so :nth-child is irrelevant there).
3997
+ -->
3998
+ <div class="repeater-wrapper" [class.has-children]="children.length > 0">
3999
+
4000
+ <!-- HAS-CHILDREN: badge outside root, absolute over wrapper -->
4001
+ <div *ngIf="children.length > 0" class="repeater-badge">
4002
+ <ng-container *ngTemplateOutlet="badgeContent"></ng-container>
3971
4003
  </div>
3972
4004
 
3973
- <!-- Template drop zone — user designs one item here -->
3974
- <div class="repeater-template"
4005
+ <div class="repeater-root"
4006
+ [ngClass]="['iox-node-' + nodeId]"
3975
4007
  ioxDropzone
3976
4008
  [ioxDropzoneId]="dropListId"
3977
4009
  [ioxDropzoneData]="children"
3978
4010
  [ioxDropzonePostDrop]="refreshPreviewsBound"
3979
4011
  (ioxDrop)="onDrop($event)">
3980
4012
 
3981
- <div *ngIf="!children.length" class="repeater-placeholder">
3982
- <i class="ph-thin ph-rows"></i>
3983
- <span>Drop a component here as the item template</span>
3984
- </div>
4013
+ <!-- EMPTY STATE: badge + placeholder inside root -->
4014
+ <ng-container *ngIf="!children.length">
4015
+ <div class="repeater-badge">
4016
+ <ng-container *ngTemplateOutlet="badgeContent"></ng-container>
4017
+ </div>
4018
+ <div class="repeater-placeholder">
4019
+ <i class="ph-thin ph-rows"></i>
4020
+ <span>Drop a component here as the item template</span>
4021
+ </div>
4022
+ </ng-container>
3985
4023
 
4024
+ <!-- Template items — DIRECT children of repeater-root.
4025
+ :first-child / :nth-child(odd) etc. now correctly target these
4026
+ as siblings of the preview items below. -->
3986
4027
  <div *ngFor="let child of children"
3987
- [ngClass]="['repeater-template-child', 'iox-outer-' + (child.styleId ?? child.id)]"
4028
+ [ngClass]="['repeater-item-template', 'iox-outer-' + (child.styleId ?? child.id)]"
3988
4029
  ioxDraggable
3989
4030
  [ioxDragData]="child"
3990
4031
  [ioxDragSourceId]="dropListId">
@@ -3995,24 +4036,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
3995
4036
  (onMouseLeave)="childMouseLeave.emit()">
3996
4037
  </ng-container>
3997
4038
  </div>
3998
- </div>
3999
4039
 
4000
- <!-- Preview items for rows 2..N one iox-outer wrapper per child so
4001
- width/margin outer props apply, and items participate directly in
4002
- the repeater-root grid/flex (template uses display:contents). -->
4003
- <ng-container *ngFor="let row of previewRows">
4004
- <div *ngFor="let child of row"
4005
- [ngClass]="['repeater-preview-child', 'iox-outer-' + (child.styleId ?? child.id)]">
4006
- <ng-container
4007
- [ioxRender]="child"
4008
- (onClick)="$event"
4009
- (onMouseEnter)="$event"
4010
- (onMouseLeave)="undefined">
4011
- </ng-container>
4012
- </div>
4013
- </ng-container>
4040
+ <!-- Preview items also DIRECT children of repeater-root. -->
4041
+ <ng-container *ngFor="let row of previewRows">
4042
+ <div *ngFor="let child of row"
4043
+ [ngClass]="['repeater-preview-child', 'iox-outer-' + (child.styleId ?? child.id)]">
4044
+ <ng-container
4045
+ [ioxRender]="child"
4046
+ (onClick)="$event"
4047
+ (onMouseEnter)="$event"
4048
+ (onMouseLeave)="undefined">
4049
+ </ng-container>
4050
+ </div>
4051
+ </ng-container>
4052
+ </div>
4014
4053
  </div>
4015
- `, standalone: false, styles: [".repeater-root{position:relative;box-sizing:border-box}.repeater-badge{display:flex;align-items:center;gap:.4rem;padding:4px 8px;font-size:11px;color:#cb9090;background:#cb909014;border:1px dashed rgba(203,144,144,.4);border-bottom:none;border-radius:4px 4px 0 0;-webkit-user-select:none;user-select:none}.repeater-root.has-children .repeater-badge{position:absolute;top:0;left:0;z-index:10;border-radius:0 0 4px;border:1px solid rgba(203,144,144,.5);opacity:0;cursor:pointer;transition:opacity .15s}.repeater-root.has-children:hover .repeater-badge{opacity:1}.repeater-root.has-children .repeater-template{border:none;border-radius:0;padding:0;min-height:unset;display:contents}.repeater-badge i{font-size:13px}.repeater-badge-empty{opacity:.55}.repeater-badge-count{margin-left:auto;font-weight:600}.repeater-badge-loading i{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.repeater-template{border:1px dashed rgba(203,144,144,.4);border-radius:0 0 4px 4px;padding:4px;min-height:40px}.repeater-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1.5rem 1rem;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none}.repeater-placeholder i{font-size:20px}.repeater-template-child{min-width:0}.repeater-preview-child{opacity:.55;pointer-events:none;min-width:0}\n"] }]
4054
+ `, standalone: false, styles: [".repeater-wrapper{position:relative;box-sizing:border-box}.repeater-badge{display:flex;align-items:center;gap:.4rem;padding:4px 8px;font-size:11px;color:#cb9090;background:#cb909014;border:1px dashed rgba(203,144,144,.4);border-bottom:none;border-radius:4px 4px 0 0;-webkit-user-select:none;user-select:none}.repeater-wrapper.has-children>.repeater-badge{position:absolute;top:0;left:0;z-index:10;border-radius:0 0 4px;border:1px solid rgba(203,144,144,.5);opacity:0;cursor:pointer;transition:opacity .15s}.repeater-wrapper.has-children:hover>.repeater-badge{opacity:1}.repeater-badge i{font-size:13px}.repeater-badge-empty{opacity:.55}.repeater-badge-count{margin-left:auto;font-weight:600}.repeater-badge-loading i{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.repeater-root{box-sizing:border-box}.repeater-wrapper:not(.has-children) .repeater-root{border:1px dashed rgba(203,144,144,.4);border-top:none;border-radius:0 0 4px 4px;min-height:40px}.repeater-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1.5rem 1rem;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none}.repeater-placeholder i{font-size:20px}.repeater-item-template{min-width:0}.repeater-preview-child{opacity:.55;pointer-events:none;min-width:0}\n"] }]
4016
4055
  }], ctorParameters: () => [{ type: DragEngineService }, { type: OverlayService }, { type: undefined, decorators: [{
4017
4056
  type: Optional
4018
4057
  }, {