@vectoriox/iox-builder 1.4.26 → 1.4.28

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.
@@ -1893,6 +1893,9 @@ class TypographyGroupStyleConfig extends GroupStyleConfig {
1893
1893
  ], 'left'),
1894
1894
  new TraitConfig('fontStyle', 'Italic', TraitInputType.SelectButton, { items: [{ value: 'italic', icon: 'ph-thin ph-text-italic', label: 'Italic' }], allowEmpty: true, noneValue: 'normal' }, 'normal', true),
1895
1895
  new TraitConfig('textDecoration', 'Underline', TraitInputType.SelectButton, { items: [{ value: 'underline', icon: 'ph-thin ph-text-underline', label: 'Underline' }], allowEmpty: true, noneValue: 'none' }, 'none', true),
1896
+ new TraitConfig('_sep_stroke', 'Stroke', TraitInputType.SectionLabel),
1897
+ new TraitConfig('WebkitTextStrokeWidth', 'Width', TraitInputType.Scrub, { min: 0, max: 10, step: 0.5, units: ['px'] }, '0px', true),
1898
+ new TraitConfig('WebkitTextStrokeColor', 'Color', TraitInputType.Color, { allowGradient: false, allowTransparent: true, formats: ['hex', 'rgb', 'hsl'] }, 'transparent', true),
1896
1899
  ]);
1897
1900
  }
1898
1901
  }
@@ -2139,13 +2142,17 @@ class StyleRegistryService {
2139
2142
  return `.${className} {\n${entries.join('\n')}\n}`;
2140
2143
  }
2141
2144
  /**
2142
- * Rewrite bare `vh` values to `calc(N * var(--preview-vh, 1vh))` so they
2143
- * resolve to the simulated viewport height in the builder canvas.
2144
- * In production (no --preview-vh defined) the fallback `1vh` preserves the
2145
- * original behaviour: `calc(50 * 1vh)` == `50vh`.
2145
+ * Rewrite viewport-relative units so they resolve to the simulated canvas
2146
+ * dimensions rather than the real browser viewport.
2147
+ *
2148
+ * --preview-vh / --preview-vw are set by BuilderComponent via ResizeObserver
2149
+ * and viewport-state subscription. In production (no variables defined) the
2150
+ * fallbacks `1vh` / `1vw` restore the original browser behaviour.
2146
2151
  */
2147
2152
  rewriteVh(value) {
2148
- return value.replace(/(-?\d*\.?\d+)vh/g, 'calc($1 * var(--preview-vh, 1vh))');
2153
+ return value
2154
+ .replace(/(-?\d*\.?\d+)vh/g, 'calc($1 * var(--preview-vh, 1vh))')
2155
+ .replace(/(-?\d*\.?\d+)vw/g, 'calc($1 * var(--preview-vw, 1vw))');
2149
2156
  }
2150
2157
  toKebabCase(str) {
2151
2158
  return str.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);
@@ -3294,18 +3301,23 @@ class BuilderComponent {
3294
3301
  }
3295
3302
  }
3296
3303
  /**
3297
- * Set --preview-vh on .preview-scroll so that 100vh fills the visible canvas
3298
- * frame at the current scale. Value = canvas frame height ÷ scale ÷ 100, so
3299
- * calc(100 * var(--preview-vh)) equals the frame height in canvas-space pixels.
3300
- * Falls back to 1vh in the live page (no --preview-vh defined there).
3304
+ * Set --preview-vh / --preview-vw on .preview-scroll so that viewport-relative
3305
+ * units (vh, vw) inside the canvas resolve to the simulated canvas dimensions
3306
+ * rather than the real browser viewport.
3307
+ *
3308
+ * --preview-vh = canvas frame height (unscaled) / 100
3309
+ * --preview-vw = canvas width from viewport state / 100
3310
+ *
3311
+ * Both fall back to their native unit in production (no variables defined).
3301
3312
  */
3302
3313
  updatePreviewVh() {
3303
3314
  const el = this.previewScrollRef?.nativeElement;
3304
3315
  if (!el)
3305
3316
  return;
3306
- const scale = this.viewportService.getState().scale;
3307
- const frameH = el.clientHeight / scale;
3317
+ const state = this.viewportService.getState();
3318
+ const frameH = el.clientHeight / state.scale;
3308
3319
  el.style.setProperty('--preview-vh', `${frameH / 100}px`);
3320
+ el.style.setProperty('--preview-vw', `${state.width / 100}px`);
3309
3321
  this.canvasFrameHeight = Math.round(frameH);
3310
3322
  }
3311
3323
  initLenis() {
@@ -3900,6 +3912,7 @@ class BuilderContainerComponent {
3900
3912
  this.style = {};
3901
3913
  this.nodeId = '';
3902
3914
  this.dropListId = '';
3915
+ this.htmlTag = 'div';
3903
3916
  this.childClick = new EventEmitter();
3904
3917
  this.childMouseEnter = new EventEmitter();
3905
3918
  this.childMouseLeave = new EventEmitter();
@@ -3919,19 +3932,12 @@ class BuilderContainerComponent {
3919
3932
  this.dragEngine.handleDrop(this.children, event, this.dropListId, this.cdr);
3920
3933
  }
3921
3934
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: BuilderContainerComponent, deps: [{ token: DragEngineService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3922
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: BuilderContainerComponent, isStandalone: false, selector: "app-builder-container", inputs: { children: "children", style: "style", nodeId: "nodeId", dropListId: "dropListId" }, outputs: { childClick: "childClick", childMouseEnter: "childMouseEnter", childMouseLeave: "childMouseLeave" }, ngImport: i0, template: `
3923
- <div class="container-root"
3924
- [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']"
3925
- ioxDropzone
3926
- [ioxDropzoneId]="dropListId"
3927
- [ioxDropzoneData]="children"
3928
- (ioxDrop)="onDrop($event)">
3929
-
3935
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: BuilderContainerComponent, isStandalone: false, selector: "app-builder-container", inputs: { children: "children", style: "style", nodeId: "nodeId", dropListId: "dropListId", htmlTag: "htmlTag" }, outputs: { childClick: "childClick", childMouseEnter: "childMouseEnter", childMouseLeave: "childMouseLeave" }, ngImport: i0, template: `
3936
+ <ng-template #dropContent>
3930
3937
  <div *ngIf="!children.length" class="container-placeholder">
3931
3938
  <i class="ph-thin ph-square"></i>
3932
3939
  <span>Drop components here</span>
3933
3940
  </div>
3934
-
3935
3941
  <div *ngFor="let child of children"
3936
3942
  [ngClass]="['container-child', 'iox-outer-' + (child.styleId ?? child.id)]"
3937
3943
  ioxDraggable
@@ -3944,24 +3950,30 @@ class BuilderContainerComponent {
3944
3950
  (onMouseLeave)="childMouseLeave.emit()">
3945
3951
  </ng-container>
3946
3952
  </div>
3947
- </div>
3948
- `, isInline: true, styles: [".container-root{position:relative;box-sizing:border-box}.container-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:0}.container-placeholder i{font-size:18px}.container-child{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"] }] }); }
3953
+ </ng-template>
3954
+
3955
+ @switch (htmlTag) {
3956
+ @case ('section') { <section class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></section> }
3957
+ @case ('article') { <article class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></article> }
3958
+ @case ('header') { <header class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></header> }
3959
+ @case ('footer') { <footer class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></footer> }
3960
+ @case ('main') { <main class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></main> }
3961
+ @case ('nav') { <nav class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></nav> }
3962
+ @case ('ul') { <ul class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></ul> }
3963
+ @case ('ol') { <ol class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></ol> }
3964
+ @case ('li') { <li class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></li> }
3965
+ @default { <div class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></div> }
3966
+ }
3967
+ `, isInline: true, styles: [".container-root{position:relative;box-sizing:border-box}.container-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:0}.container-placeholder i{font-size:18px}.container-child{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"] }] }); }
3949
3968
  }
3950
3969
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: BuilderContainerComponent, decorators: [{
3951
3970
  type: Component,
3952
3971
  args: [{ selector: 'app-builder-container', template: `
3953
- <div class="container-root"
3954
- [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']"
3955
- ioxDropzone
3956
- [ioxDropzoneId]="dropListId"
3957
- [ioxDropzoneData]="children"
3958
- (ioxDrop)="onDrop($event)">
3959
-
3972
+ <ng-template #dropContent>
3960
3973
  <div *ngIf="!children.length" class="container-placeholder">
3961
3974
  <i class="ph-thin ph-square"></i>
3962
3975
  <span>Drop components here</span>
3963
3976
  </div>
3964
-
3965
3977
  <div *ngFor="let child of children"
3966
3978
  [ngClass]="['container-child', 'iox-outer-' + (child.styleId ?? child.id)]"
3967
3979
  ioxDraggable
@@ -3974,7 +3986,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
3974
3986
  (onMouseLeave)="childMouseLeave.emit()">
3975
3987
  </ng-container>
3976
3988
  </div>
3977
- </div>
3989
+ </ng-template>
3990
+
3991
+ @switch (htmlTag) {
3992
+ @case ('section') { <section class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></section> }
3993
+ @case ('article') { <article class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></article> }
3994
+ @case ('header') { <header class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></header> }
3995
+ @case ('footer') { <footer class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></footer> }
3996
+ @case ('main') { <main class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></main> }
3997
+ @case ('nav') { <nav class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></nav> }
3998
+ @case ('ul') { <ul class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></ul> }
3999
+ @case ('ol') { <ol class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></ol> }
4000
+ @case ('li') { <li class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></li> }
4001
+ @default { <div class="container-root" [ngClass]="['iox-node-' + nodeId, listOrientation === 'horizontal' ? 'is-horizontal' : '']" ioxDropzone [ioxDropzoneId]="dropListId" [ioxDropzoneData]="children" (ioxDrop)="onDrop($event)"><ng-container [ngTemplateOutlet]="dropContent"></ng-container></div> }
4002
+ }
3978
4003
  `, standalone: false, styles: [".container-root{position:relative;box-sizing:border-box}.container-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:0}.container-placeholder i{font-size:18px}.container-child{min-width:0}\n"] }]
3979
4004
  }], ctorParameters: () => [{ type: DragEngineService }, { type: i0.ChangeDetectorRef }], propDecorators: { children: [{
3980
4005
  type: Input
@@ -3984,6 +4009,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
3984
4009
  type: Input
3985
4010
  }], dropListId: [{
3986
4011
  type: Input
4012
+ }], htmlTag: [{
4013
+ type: Input
3987
4014
  }], childClick: [{
3988
4015
  type: Output
3989
4016
  }], childMouseEnter: [{
@@ -5062,7 +5089,9 @@ class BuilderContainerComponentConfig extends ComponentConfig {
5062
5089
  constructor() {
5063
5090
  super('Container', 'app-builder-container', 'ph-thin ph-square', 'Layout');
5064
5091
  this.children = [];
5065
- this.traits = [];
5092
+ this.traits = [
5093
+ new TraitConfig('htmlTag', 'HTML Tag', TraitInputType.Select, ['div', 'section', 'article', 'header', 'footer', 'main', 'nav', 'ul', 'ol', 'li'], 'div'),
5094
+ ];
5066
5095
  this.styleTraits = buildFullStyleTraits();
5067
5096
  this.applyStyleDefaults({
5068
5097
  width: '100%',