@vectoriox/iox-builder 4.24.0 → 4.26.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/fesm2022/vectoriox-iox-builder.mjs +238 -11
- package/fesm2022/vectoriox-iox-builder.mjs.map +1 -1
- package/index.d.ts +61 -15
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import { InputTextModule } from 'primeng/inputtext';
|
|
|
15
15
|
import { SelectModule } from 'primeng/select';
|
|
16
16
|
import { TooltipModule } from 'primeng/tooltip';
|
|
17
17
|
import { DialogModule } from 'primeng/dialog';
|
|
18
|
-
import * as
|
|
18
|
+
import * as i2$2 from '@vectoriox/iox-ui';
|
|
19
19
|
import { VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, resolveFlavorDefaults, Breakpoint, BREAKPOINTS, countOverrides, setOverride, DEFAULT_FLAVOR, breakpointDef, breakpointForWidth, FormRenderState, safeSetInput, ContextStore, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, DeclarationContext, buildPartSelector, planResponsiveRules, resolveStyleProps, buildTargetedStateSelector, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, composeVirtualTraits, stateNamesIn, partClassName, resolveInputs, setInputOverride, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, resolveBoundValue, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
|
|
20
20
|
export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTraits } from '@vectoriox/iox-ui';
|
|
21
21
|
import Lenis from 'lenis';
|
|
@@ -83,6 +83,8 @@ const INVERSE_ACTION = {
|
|
|
83
83
|
// `contextActionEffect` (@vectoriox/iox-ui).
|
|
84
84
|
setContext: 'clearContext',
|
|
85
85
|
clearContext: 'setContext',
|
|
86
|
+
openDialog: 'closeDialog',
|
|
87
|
+
closeDialog: 'openDialog',
|
|
86
88
|
};
|
|
87
89
|
const TRIGGER_OPTIONS = [
|
|
88
90
|
{ value: 'pageLoad', label: 'Page load', icon: 'ph-thin ph-play' },
|
|
@@ -106,9 +108,14 @@ const ACTION_TYPE_OPTIONS = [
|
|
|
106
108
|
{ value: 'show', label: 'Show' },
|
|
107
109
|
{ value: 'hide', label: 'Hide' },
|
|
108
110
|
{ value: 'toggleVisibility', label: 'Toggle visibility' },
|
|
111
|
+
{ value: 'openDialog', label: 'Open dialog' },
|
|
112
|
+
{ value: 'closeDialog', label: 'Close dialog' },
|
|
113
|
+
{ value: 'toggleDialog', label: 'Toggle dialog' },
|
|
109
114
|
{ value: 'setContext', label: 'Set context' },
|
|
110
115
|
{ value: 'clearContext', label: 'Clear context' },
|
|
111
116
|
];
|
|
117
|
+
/** Dialog actions, for the engines' dispatch branch (mirror of SWIPER's set). */
|
|
118
|
+
const DIALOG_ACTION_TYPES = new Set(['openDialog', 'closeDialog', 'toggleDialog']);
|
|
112
119
|
const EASING_OPTIONS$1 = ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out'];
|
|
113
120
|
/** Interaction pseudo-classes — compiled to .iox-node-{id}:state */
|
|
114
121
|
const INTERACTION_STATES = ['hover', 'active', 'focus'];
|
|
@@ -345,19 +352,19 @@ class PositionGroupStyleConfig extends GroupStyleConfig {
|
|
|
345
352
|
class LayoutGroupStyleConfig extends GroupStyleConfig {
|
|
346
353
|
constructor() {
|
|
347
354
|
super(StyleCategory.Layout, [
|
|
348
|
-
new TraitConfig('display', 'Display', TraitInputType.Select, ['block', 'inline', 'inline-block', 'flex', 'grid'], 'block'),
|
|
355
|
+
new TraitConfig('display', 'Display', TraitInputType.Select, ['block', 'inline', 'inline-block', 'flex', 'inline-flex', 'grid'], 'block'),
|
|
349
356
|
// ── Flex-only ─────────────────────────────────────────────────────
|
|
350
357
|
new TraitConfig('flexDirection', 'Direction', TraitInputType.SelectButton, [
|
|
351
358
|
{ value: 'row', label: 'Horizontal', icon: 'ph-thin ph-arrow-right' },
|
|
352
359
|
{ value: 'row-reverse', label: 'Horizontal Reversed', icon: 'ph-thin ph-arrow-left' },
|
|
353
360
|
{ value: 'column', label: 'Vertical', icon: 'ph-thin ph-arrow-down' },
|
|
354
361
|
{ value: 'column-reverse', label: 'Vertical Reversed', icon: 'ph-thin ph-arrow-up' },
|
|
355
|
-
], 'row', false, { trait: 'display', values: 'flex' }),
|
|
362
|
+
], 'row', false, { trait: 'display', values: ['flex', 'inline-flex'] }),
|
|
356
363
|
new TraitConfig('flexWrap', 'Flex Wrap', TraitInputType.SelectButton, [
|
|
357
364
|
{ value: 'nowrap', label: 'No Wrap', icon: 'ph-thin ph-minus' },
|
|
358
365
|
{ value: 'wrap', label: 'Wrap', icon: 'ph-thin ph-arrow-elbow-down-right' },
|
|
359
366
|
{ value: 'wrap-reverse', label: 'Wrap Reversed', icon: 'ph-thin ph-arrow-elbow-up-right' },
|
|
360
|
-
], 'nowrap', false, { trait: 'display', values: 'flex' }),
|
|
367
|
+
], 'nowrap', false, { trait: 'display', values: ['flex', 'inline-flex'] }),
|
|
361
368
|
// ── Shared flex + grid ────────────────────────────────────────────
|
|
362
369
|
new TraitConfig('justifyContent', 'Justify', TraitInputType.SelectButton, [
|
|
363
370
|
{ value: 'flex-start', label: 'Start', icon: 'ph-thin ph-align-left' },
|
|
@@ -366,14 +373,14 @@ class LayoutGroupStyleConfig extends GroupStyleConfig {
|
|
|
366
373
|
{ value: 'space-between', label: 'Space Between', icon: 'ph-thin ph-arrows-out-line-horizontal' },
|
|
367
374
|
{ value: 'space-around', label: 'Space Around', icon: 'ph-thin ph-dots-three' },
|
|
368
375
|
{ value: 'space-evenly', label: 'Space Evenly', icon: 'ph-thin ph-dots-six' },
|
|
369
|
-
], 'flex-start', false, { trait: 'display', values: ['flex', 'grid'] }),
|
|
376
|
+
], 'flex-start', false, { trait: 'display', values: ['flex', 'inline-flex', 'grid'] }),
|
|
370
377
|
new TraitConfig('alignItems', 'Align Items', TraitInputType.SelectButton, [
|
|
371
378
|
{ value: 'stretch', label: 'Stretch', icon: 'ph-thin ph-arrows-vertical' },
|
|
372
379
|
{ value: 'start', label: 'Start', icon: 'ph-thin ph-align-top' },
|
|
373
380
|
{ value: 'center', label: 'Center', icon: 'ph-thin ph-align-center-vertical' },
|
|
374
381
|
{ value: 'end', label: 'End', icon: 'ph-thin ph-align-bottom' },
|
|
375
|
-
], 'stretch', false, { trait: 'display', values: ['flex', 'grid'] }),
|
|
376
|
-
new TraitConfig('gap', 'Gap', TraitInputType.Scrub, { min: 0, max: 200, step: 1, units: UNITS_FIXED }, '0px', false, { trait: 'display', values: ['flex', 'grid'] }),
|
|
382
|
+
], 'stretch', false, { trait: 'display', values: ['flex', 'inline-flex', 'grid'] }),
|
|
383
|
+
new TraitConfig('gap', 'Gap', TraitInputType.Scrub, { min: 0, max: 200, step: 1, units: UNITS_FIXED }, '0px', false, { trait: 'display', values: ['flex', 'inline-flex', 'grid'] }),
|
|
377
384
|
// ── Grid-only ─────────────────────────────────────────────────────
|
|
378
385
|
new TraitConfig('gridTemplateColumns', 'Columns', TraitInputType.GridTemplate, undefined, '1fr', false, { trait: 'display', values: 'grid' }),
|
|
379
386
|
new TraitConfig('gridTemplateRows', 'Rows', TraitInputType.GridTemplate, undefined, 'auto', false, { trait: 'display', values: 'grid' }),
|
|
@@ -410,8 +417,11 @@ class LayoutGroupStyleConfig extends GroupStyleConfig {
|
|
|
410
417
|
// is hidden and the style panel drops the whole (now-empty) group. `align-self`/`order`
|
|
411
418
|
// apply to both flex and grid items; `justify-self`/`grid-column`/`grid-row` are grid-only;
|
|
412
419
|
// `flex-grow`/`flex-shrink`/`flex-basis` are flex-only.
|
|
413
|
-
|
|
414
|
-
|
|
420
|
+
// 'inline-flex' IS flex for every layout question asked here — ButtonBlock has shipped it as a
|
|
421
|
+
// constructor default forever, which made Layout badge "4" with three of the four controls hidden
|
|
422
|
+
// and the Display select blank (no option for its own value). The families, not the keywords.
|
|
423
|
+
const PARENT_FLEX_OR_GRID = { trait: 'display', values: ['flex', 'inline-flex', 'grid'], scope: 'parent' };
|
|
424
|
+
const PARENT_FLEX = { trait: 'display', values: ['flex', 'inline-flex'], scope: 'parent' };
|
|
415
425
|
const PARENT_GRID = { trait: 'display', values: 'grid', scope: 'parent' };
|
|
416
426
|
class ChildLayoutGroupStyleConfig extends GroupStyleConfig {
|
|
417
427
|
constructor() {
|
|
@@ -3251,6 +3261,13 @@ class InteractionEngineService {
|
|
|
3251
3261
|
this.executeSwiperAction(action);
|
|
3252
3262
|
continue;
|
|
3253
3263
|
}
|
|
3264
|
+
// Dialog actions (A1b): the canvas RUNS them — styling a dialog you cannot open is
|
|
3265
|
+
// impossible. The canvas twin registered open/close/toggle under its nodeId, exactly
|
|
3266
|
+
// the Swiper-method pattern; a missing/mistargeted id is a silent no-op, never a throw.
|
|
3267
|
+
if (DIALOG_ACTION_TYPES.has(action.type)) {
|
|
3268
|
+
this.executeDialogAction(action);
|
|
3269
|
+
continue;
|
|
3270
|
+
}
|
|
3254
3271
|
// Context actions write STATE, not animation. `selfEl` is deliberate: $item is read by
|
|
3255
3272
|
// walking up from the element actually hovered/clicked, which for a repeater PREVIEW ROW
|
|
3256
3273
|
// is the clone — so each row publishes its own item, exactly as on the live site.
|
|
@@ -3300,6 +3317,22 @@ class InteractionEngineService {
|
|
|
3300
3317
|
// MERGE, not replace — a page can hold several repeaters, each publishing its own source.
|
|
3301
3318
|
this.contextData = { ...this.contextData, ...(data ?? {}) };
|
|
3302
3319
|
}
|
|
3320
|
+
executeDialogAction(action) {
|
|
3321
|
+
const dialog = action.target && action.target !== 'self' ? this.instanceRegistry.get(action.target) : null;
|
|
3322
|
+
if (!dialog)
|
|
3323
|
+
return;
|
|
3324
|
+
switch (action.type) {
|
|
3325
|
+
case 'openDialog':
|
|
3326
|
+
dialog.open?.();
|
|
3327
|
+
break;
|
|
3328
|
+
case 'closeDialog':
|
|
3329
|
+
dialog.close?.();
|
|
3330
|
+
break;
|
|
3331
|
+
case 'toggleDialog':
|
|
3332
|
+
dialog.toggle?.();
|
|
3333
|
+
break;
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3303
3336
|
executeSwiperAction(action) {
|
|
3304
3337
|
// Target is the nodeId of the SliderContainer to control.
|
|
3305
3338
|
const swiper = this.instanceRegistry.get(action.target);
|
|
@@ -7207,7 +7240,7 @@ class BuilderComponent {
|
|
|
7207
7240
|
}
|
|
7208
7241
|
}
|
|
7209
7242
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderComponent, deps: [{ token: ComponentRegistryService }, { token: OverlayService }, { token: PanelEventService }, { token: DragEngineService }, { token: DataSourceRegistryService }, { token: ViewportService }, { token: FormStateService }, { token: InteractionEngineService }, { token: InteractionPresetRegistryService }, { token: BuilderClipboardService }, { token: SymbolRegistryService }, { token: i0.ChangeDetectorRef }, { token: i0.ApplicationRef }, { token: MoveableCanvasService }, { token: SelectoCanvasService }, { token: StyleRegistryService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7210
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: BuilderComponent, isStandalone: false, selector: "app-builder", inputs: { layout: "layout", dataSources: "dataSources", orgId: "orgId", routeParams: "routeParams", pageName: "pageName", isSaving: "isSaving", pageStatus: "pageStatus", pageSettings: "pageSettings", globalElements: "globalElements", canUndo: "canUndo", canRedo: "canRedo", moveableMode: "moveableMode" }, outputs: { save: "save", undo: "undo", redo: "redo", back: "back", preview: "preview", publishToggle: "publishToggle", pageSettingsChange: "pageSettingsChange", applyAnimationToAll: "applyAnimationToAll", saveBlock: "saveBlock", globalElementsChange: "globalElementsChange" }, viewQueries: [{ propertyName: "previewCanvas", first: true, predicate: ["previewCanvas"], descendants: true }, { propertyName: "previewScrollRef", first: true, predicate: ["previewScroll"], descendants: true }, { propertyName: "lenisContentRef", first: true, predicate: ["lenisContent"], descendants: true }, { propertyName: "globalOverlayRef", first: true, predicate: ["globalOverlay"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"builder\">\n <header class=\"builder-header\">\n <div class=\"sidebar-switcher\">\n <button (click)=\"activeSidebar = 'pages'\" [class.active]=\"activeSidebar === 'pages'\" title=\"Pages\" aria-label=\"Pages\">\n <i class=\"ph-thin ph-browsers\"></i>\n </button>\n <button (click)=\"activeSidebar = 'components'\" [class.active]=\"activeSidebar === 'components'\" title=\"Components\" aria-label=\"Components\">\n <i class=\"ph-thin ph-cube\"></i>\n </button>\n <button (click)=\"activeSidebar = 'tree'\" [class.active]=\"activeSidebar === 'tree'\" title=\"Layers\" aria-label=\"Layers\">\n <i class=\"ph-thin ph-tree-structure\"></i>\n </button>\n <button (click)=\"activeSidebar = 'tokens'\" [class.active]=\"activeSidebar === 'tokens'\" title=\"Design Tokens\" aria-label=\"Design Tokens\">\n <i class=\"ph-thin ph-circles-three\"></i>\n </button>\n </div>\n\n <app-toolbar\n [activeMode]=\"activeMode\"\n [activeBreakpoint]=\"activeBreakpoint\"\n [breakpointCounts]=\"breakpointCounts\"\n [auditCount]=\"auditFindings.length\"\n [auditOpen]=\"auditOpen\"\n [activeZoom]=\"activeZoom\"\n [activeScreenWidth]=\"activeScreenWidth\"\n [isSaving]=\"isSaving\"\n [pageStatus]=\"pageStatus\"\n [canUndo]=\"canUndo\"\n [canRedo]=\"canRedo\"\n (modeChange)=\"handleToolbarModeChange($event)\"\n (breakpointChange)=\"handleToolbarBreakpointChange($event)\"\n (auditToggle)=\"toggleAudit()\"\n (zoomChange)=\"handleToolbarZoomChange($event)\"\n (screenWidthChange)=\"handleToolbarScreenWidthChange($event)\"\n (save)=\"save.emit()\"\n (preview)=\"preview.emit()\"\n (publishToggle)=\"publishToggle.emit()\"\n (undo)=\"undo.emit()\"\n (redo)=\"redo.emit()\">\n </app-toolbar>\n\n <div class=\"panel-switcher\">\n <button (click)=\"selectPanel(panelTypes.BINDINGS)\" [class.active]=\"activePanel === panelTypes.BINDINGS\" title=\"Bindings\">\n <i class=\"ph-thin ph-plugs-connected\"></i>\n </button>\n <button (click)=\"selectPanel(panelTypes.STYLES)\" [class.active]=\"activePanel === panelTypes.STYLES\" title=\"Styles\">\n <i class=\"ph-thin ph-paint-brush\"></i>\n </button>\n <button (click)=\"selectPanel(panelTypes.PAGE)\" [class.active]=\"activePanel === panelTypes.PAGE\" title=\"Page settings\" aria-label=\"Page settings\">\n <i class=\"ph-thin ph-gear-six\"></i>\n </button>\n <button (click)=\"selectPanel(panelTypes.INTERACTIONS)\" [class.active]=\"activePanel === panelTypes.INTERACTIONS\" title=\"Interactions\">\n <i class=\"ph-thin ph-lightning\"></i>\n </button>\n </div> \n </header>\n\n <div class=\"builder-main\" [class.panel-open]=\"isPanelOpen\">\n <aside class=\"sidebar\">\n <div *ngIf=\"activeSidebar === 'pages'\" class=\"sidebar-slot\">\n <ng-content select=\"[builderPages]\"></ng-content>\n </div>\n <div *ngIf=\"activeSidebar === 'components'\" class=\"sidebar-slot\">\n <ng-content select=\"[builderComponents]\"></ng-content>\n </div>\n <div *ngIf=\"activeSidebar === 'tokens'\" class=\"sidebar-slot\">\n <ng-content select=\"[builderTokens]\"></ng-content>\n </div>\n <app-layer-tree *ngIf=\"activeSidebar === 'tree'\"\n [layout]=\"layout\"\n [globalElements]=\"globalElements\"\n (nodeSelect)=\"onTreeNodeSelect($event)\"\n (nodeAction)=\"onTreeNodeAction($event)\"\n (nodeMove)=\"onTreeNodeMove()\"></app-layer-tree>\n </aside>\n\n <main #previewCanvas class=\"preview\"\n [class.grab-mode]=\"activeMode === builderModes.Pan\"\n [class.grabbing]=\"isPanning\"\n (click)=\"handleCanvasClick()\"\n (mousedown)=\"onBoardMouseDown($event)\"\n (mousemove)=\"onBoardMouseMove($event)\"\n (mouseup)=\"onBoardMouseUp()\"\n (mouseleave)=\"onBoardMouseUp()\">\n <app-overlay (toolbarAction)=\"onToolbarAction($event)\"></app-overlay>\n\n <!-- Element path \u2014 pinned to the PREVIEW VIEWPORT, not to the canvas frame. The frame\n pans and scales; a breadcrumb that tracked its edge would drift off-screen and\n shrink with zoom. Sits in the gutter above the frame (see $canvas-inset-block-start).\n\n \u26A0\uFE0F stopPropagation is REQUIRED, not defensive. This element lives inside .preview,\n whose (click) is handleCanvasClick() \u2014 \"you clicked empty canvas, drop the\n selection\". Without it, picking an ancestor crumb selects that node and then\n immediately bubbles into the canvas handler, which clears it: the selection and the\n layer-tree highlight both fall back to Body. Same reason .audit-dock stops its own. -->\n <app-breadcrumb-bar\n (click)=\"$event.stopPropagation()\"\n [path]=\"selectedPath\"\n (nodeSelect)=\"onCrumbSelect($event)\"\n (rootSelect)=\"onCrumbRootSelect()\"\n (nodePeek)=\"onCrumbPeek($event)\">\n </app-breadcrumb-bar>\n\n <!-- Responsive audit (A5) \u2014 floats over the canvas, right gutter. -->\n @if (auditOpen) {\n <div class=\"audit-dock\" (click)=\"$event.stopPropagation()\">\n <app-audit-panel\n [findings]=\"auditFindings\"\n [breakpointLabel]=\"auditBreakpointLabel\"\n [running]=\"auditRunning\"\n (select)=\"selectAuditNode($event)\"\n (fix)=\"applyAuditFix($event)\"\n (fixAll)=\"applyAllAuditFixes()\"\n (rerun)=\"runAudit()\"\n (closePanel)=\"toggleAudit()\"></app-audit-panel>\n </div>\n }\n\n <!-- Custom Lenis scrollbar \u2014 lives in .preview (not .preview-scroll) so it\n stays in the right gutter and never overlaps the canvas at large widths.\n No translateY counteract needed since it isn't inside the Lenis wrapper. -->\n <div class=\"canvas-scrollbar\"\n [class.visible]=\"isScrollbarVisible\">\n <div class=\"canvas-scrollbar-thumb\"\n [style.height.px]=\"scrollThumbHeight\"\n [style.top.px]=\"scrollThumbTop\">\n </div>\n </div>\n\n <!-- Global elements overlay \u2014 outside Lenis so position:fixed children\n stay pinned to the canvas viewport rather than scrolling with content.\n Shares viewportTransform so elements scale correctly at any zoom level.\n Height matches viewportHeight so position:fixed + inset:0 fills the\n simulated viewport correctly (CSS calc(100%) would give the wrong\n containing-block height and break full-screen fixed overlays). -->\n <div *ngIf=\"globalElements.length\"\n #globalOverlay\n class=\"global-elements-overlay\"\n [style.width.px]=\"viewportWidth\"\n [style.height.px]=\"canvasFrameHeight || viewportHeight\"\n [style.transform]=\"viewportTransform\">\n <ng-container *ngFor=\"let item of globalElementsBefore\">\n <ng-container [ioxRender]=\"item\"\n (onClick)=\"handleClick($event)\"\n (onMouseEnter)=\"handleMouseEnter($event)\"\n (onMouseLeave)=\"handleMouseLeave()\">\n </ng-container>\n </ng-container>\n <ng-container *ngFor=\"let item of globalElementsAfter\">\n <ng-container [ioxRender]=\"item\"\n (onClick)=\"handleClick($event)\"\n (onMouseEnter)=\"handleMouseEnter($event)\"\n (onMouseLeave)=\"handleMouseLeave()\">\n </ng-container>\n </ng-container>\n </div>\n\n <div class=\"preview-scroll\"\n #previewScroll\n [style.width.px]=\"viewportScaledWidth\"\n [class.pan-mode]=\"activeMode === builderModes.Pan\">\n\n <!-- Lenis content proxy: height = realContentHeight \u00D7 scale.\n Lenis scrolls against this value so scroll range is always in\n visual px \u2014 correct at any zoom level. -->\n <div class=\"preview-lenis-content\" #lenisContent\n [style.height.px]=\"scaledContentHeight\">\n\n <iox-page-component\n [style.width.px]=\"viewportWidth\"\n [style.height.px]=\"canvasFrameHeight || viewportHeight\"\n [style.transform]=\"viewportTransform\">\n\n <!-- ngStyle carries the page's own background/typography (pageSettings.style),\n compiled by the SAME function the engine applies to <body>. Inline wins over\n the #canvas-preview white default, which stays as the unset fallback. -->\n <div class=\"canvas-viewport\"\n id=\"canvas-preview\"\n [ngStyle]=\"pageStyleCss\"\n [style.min-height.px]=\"canvasMinHeight\">\n\n <!-- Empty page (B4): a starting point beats a blank canvas. Each starter is\n a responsive layout preset \u2014 ordinary nodes, editable afterwards. -->\n @if (isPageEmpty) {\n <div class=\"empty-canvas\" (click)=\"$event.stopPropagation()\">\n <h2 class=\"empty-title\">Start with a layout</h2>\n <p class=\"empty-sub\">Each one already adapts to tablet and phone. You can edit or take it apart afterwards.</p>\n <div class=\"empty-grid\">\n @for (starter of starterLayouts; track starter.id) {\n <button type=\"button\" class=\"empty-card\" (click)=\"startWithLayout(starter)\">\n <i [class]=\"starter.icon\" aria-hidden=\"true\"></i>\n <span class=\"empty-card-name\">{{ starter.name }}</span>\n <span class=\"empty-card-desc\">{{ starter.description }}</span>\n </button>\n }\n </div>\n <button type=\"button\" class=\"empty-link\" (click)=\"browseComponents()\">Or start from a single element</button>\n </div>\n }\n\n <!-- WRAPPER COLLAPSE (task 9c): top-level nodes render DIRECTLY into the\n canvas viewport \u2014 no .preview-node wrapper; iox-outer + drag move to the\n host (RenderDirective, via ioxDragSourceId). -->\n <ng-container *ngFor=\"let item of layout\"\n [ioxRender]=\"item\"\n [ioxDragSourceId]=\"'canvas-preview'\"\n (onClick)=\"handleClick($event)\"\n (onMouseEnter)=\"handleMouseEnter($event)\"\n (onMouseLeave)=\"handleMouseLeave()\">\n </ng-container>\n </div>\n </iox-page-component>\n </div>\n </div>\n </main>\n\n <ng-content select=\"[builderPanel]\"></ng-content>\n </div>\n\n <!-- Save as Reusable Block dialog -->\n @if (showSaveBlockDialog) {\n <div class=\"save-block-backdrop\" (click)=\"cancelSaveBlock()\"></div>\n <div class=\"save-block-dialog\" (click)=\"$event.stopPropagation()\">\n <h4 class=\"save-block-title\">Save as Reusable Block</h4>\n <input class=\"save-block-input\"\n type=\"text\"\n placeholder=\"Block name...\"\n [(ngModel)]=\"saveBlockName\"\n (keydown.enter)=\"confirmSaveBlock()\"\n (keydown.escape)=\"cancelSaveBlock()\"\n autofocus>\n <div class=\"save-block-actions\">\n <p-button size=\"small\" severity=\"secondary\" label=\"Cancel\" (click)=\"cancelSaveBlock()\"></p-button>\n <p-button size=\"small\" label=\"Save\" [disabled]=\"!saveBlockName.trim()\" (click)=\"confirmSaveBlock()\"></p-button>\n </div>\n </div>\n }\n</div>", styles: ["@charset \"UTF-8\";:host{display:flex;flex:1;min-height:0;overflow:hidden}.builder{display:flex;flex-direction:column;direction:ltr;width:100%;height:100%;min-height:0;border-radius:0;overflow:hidden;position:relative}.builder .builder-header{background:var(--p-surface-0);padding:.375rem .75rem;border-bottom:1px solid var(--p-surface-200);display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:.5rem;flex-shrink:0}.builder .builder-header .header-back{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:6px;cursor:pointer;color:var(--p-text-muted-color);font-size:16px;transition:background .15s ease-out;margin-inline-end:.25rem}.builder .builder-header .header-back:hover{background:var(--p-surface-50);color:var(--p-text-color)}.builder .builder-header .header-page-name{flex:1;text-align:center;font-size:.8rem;font-weight:500;color:var(--p-text-muted-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-inline:1rem}.builder .sidebar-switcher,.builder .panel-switcher{display:flex;gap:.25rem}.builder .sidebar-switcher button,.builder .panel-switcher button{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:6px;border:none;background:transparent;color:var(--p-text-muted-color);cursor:pointer;font-size:1rem;transition:background .15s ease-out,color .15s ease-out}.builder .sidebar-switcher button i,.builder .panel-switcher button i{pointer-events:none}.builder .sidebar-switcher button:hover,.builder .panel-switcher button:hover{background:var(--p-surface-50);color:var(--p-text-color)}.builder .sidebar-switcher button.active,.builder .panel-switcher button.active{background:#cb9090;color:#fff}.builder .panel-switcher{justify-self:end}.builder .builder-main{display:flex;flex:1 1 0;min-height:0;position:relative;overflow:hidden}.builder .sidebar{width:260px;min-width:260px;background:var(--p-surface-0);border-inline-end:1px solid var(--p-surface-200);overflow-y:auto;overflow-x:hidden;flex-shrink:0}.builder .preview{flex:1 1 0;min-width:0;min-height:0;position:relative;overflow:hidden}.builder .preview.grab-mode{cursor:grab}.builder .preview.grab-mode iox-page-component{pointer-events:none}.builder .preview.grabbing{cursor:grabbing}.builder .canvas-scrollbar{position:absolute;right:4px;top:46px;bottom:20px;width:6px;z-index:20;opacity:0;transition:opacity .2s ease;pointer-events:none}.builder .canvas-scrollbar.visible{opacity:1}.builder .canvas-scrollbar-thumb{position:absolute;left:0;width:100%;background:#00000059;border-radius:3px;transition:top .05s linear}.builder .preview-scroll{position:absolute;inset:46px auto 20px;inset-inline-start:50%;transform:translate(-50%);max-width:calc(100% - 40px);height:calc(100% - 66px);overflow:hidden}.builder .preview-lenis-content{position:relative;width:100%;overflow:hidden;contain:paint}.builder iox-page-component{position:absolute!important;top:0;bottom:auto!important;right:auto!important;left:50%;transform-origin:top center;overflow:visible!important;container:iox-canvas/inline-size;box-shadow:0 1px 4px #00000014,0 4px 16px #0000000a;transition:width .25s ease,transform .25s ease}.builder iox-page-component ::ng-deep .iox-page-wrapper{height:auto!important;overflow:visible!important}.builder #canvas-preview{background:#fff}.builder .empty-canvas{max-inline-size:560px;margin:0 auto;padding:48px 24px;text-align:center;color:#4b5563}.builder .empty-title{margin:0;font-size:18px;font-weight:600;color:#111827}.builder .empty-sub{margin:6px 0 20px;font-size:12px;line-height:1.5;color:#6b7280}.builder .empty-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.builder .empty-card{display:flex;flex-direction:column;align-items:center;gap:4px;padding:14px 10px;border:1px solid #e5e7eb;border-radius:10px;background:#fff;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}.builder .empty-card:hover{border-color:#cb9090;box-shadow:0 2px 10px #0000000f}.builder .empty-card:focus-visible{outline:2px solid #cb9090;outline-offset:2px}.builder .empty-card i{font-size:20px;color:#a05c5c}.builder .empty-card-name{font-size:11.5px;font-weight:600;color:#111827}.builder .empty-card-desc{font-size:9.5px;line-height:1.35;color:#6b7280}.builder .empty-link{margin-block-start:16px;padding:0;border:none;background:none;font-size:11px;color:#a05c5c;cursor:pointer}.builder .empty-link:hover{text-decoration:underline}.builder .empty-link:focus-visible{outline:2px solid #cb9090;outline-offset:2px}.builder app-breadcrumb-bar{position:absolute;inset-block-start:12px;inset-inline-start:20px;inset-inline-end:56px;z-index:20;pointer-events:none}.builder .audit-dock{position:absolute;inset-block-start:46px;inset-inline-end:16px;z-index:20}.builder .global-elements-overlay{position:absolute;top:46px;left:50%;transform-origin:top center;pointer-events:none;z-index:9;overflow:hidden;container:iox-canvas/inline-size}.builder .global-elements-overlay ::ng-deep>*{pointer-events:auto}.builder .preview-node.is-selected{cursor:grab}.builder .empty-state{min-height:240px;border:1px dashed var(--p-surface-200);border-radius:10px;display:flex;align-items:center;justify-content:center;color:var(--p-text-muted-color);text-align:center;padding:1rem}.save-block-backdrop{position:fixed;inset:0;z-index:1000;background:#00000040}.save-block-dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1001;background:#fff;border-radius:8px;box-shadow:0 8px 32px #0000002e;padding:24px;width:320px}.save-block-dialog .save-block-title{margin:0 0 16px;font-size:14px;font-weight:600;color:var(--p-text-color, #333)}.save-block-dialog .save-block-input{width:100%;padding:8px 10px;border:1px solid var(--p-surface-300, #d1d5db);border-radius:6px;font-size:13px;outline:none;box-sizing:border-box;margin-bottom:16px}.save-block-dialog .save-block-input:focus{border-color:#cb9090;box-shadow:0 0 0 2px #cb909033}.save-block-dialog .save-block-actions{display:flex;justify-content:flex-end;gap:8px}::ng-deep .moveable-control-box.iox-moveable-silent{z-index:1000!important}::ng-deep .moveable-control-box.iox-moveable-silent .moveable-line,::ng-deep .moveable-control-box.iox-moveable-silent .moveable-rotation,::ng-deep .moveable-control-box.iox-moveable-silent .moveable-rotation-line{display:none!important}::ng-deep .moveable-control-box.iox-moveable-silent .moveable-control{display:block!important;width:10px!important;height:10px!important;margin-top:-5px!important;margin-left:-5px!important;background:#fff!important;border:1.5px solid #cb9090!important;border-radius:2px!important;box-shadow:0 1px 3px #0003!important}\n"], dependencies: [{ 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.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i16.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i16.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i16.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i17.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i18.IoxPageComponent, selector: "iox-page-component", inputs: ["class"], outputs: ["scrollEvent"] }, { kind: "directive", type: RenderDirective, selector: "[ioxRender]", inputs: ["ioxRender", "ioxDragSourceId"], outputs: ["onClick", "onMouseEnter", "onMouseLeave"] }, { kind: "component", type: OverlayComponent, selector: "app-overlay", outputs: ["toolbarAction"] }, { kind: "component", type: ToolbarComponent, selector: "app-toolbar", inputs: ["activeMode", "activeBreakpoint", "breakpointCounts", "auditCount", "auditOpen", "activeZoom", "activeScreenWidth", "canUndo", "canRedo", "isSaving", "pageStatus"], outputs: ["modeChange", "breakpointChange", "auditToggle", "zoomChange", "screenWidthChange", "undo", "redo", "save", "preview", "publishToggle"] }, { kind: "component", type: LayerTreeComponent, selector: "app-layer-tree", inputs: ["layout", "globalElements"], outputs: ["nodeSelect", "nodeAction", "nodeMove"] }, { kind: "component", type: BreadcrumbBarComponent, selector: "app-breadcrumb-bar", inputs: ["path"], outputs: ["nodeSelect", "rootSelect", "nodePeek"] }, { kind: "component", type: AuditPanelComponent, selector: "app-audit-panel", inputs: ["findings", "breakpointLabel", "running"], outputs: ["select", "fix", "fixAll", "rerun", "closePanel"] }] }); }
|
|
7243
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: BuilderComponent, isStandalone: false, selector: "app-builder", inputs: { layout: "layout", dataSources: "dataSources", orgId: "orgId", routeParams: "routeParams", pageName: "pageName", isSaving: "isSaving", pageStatus: "pageStatus", pageSettings: "pageSettings", globalElements: "globalElements", canUndo: "canUndo", canRedo: "canRedo", moveableMode: "moveableMode" }, outputs: { save: "save", undo: "undo", redo: "redo", back: "back", preview: "preview", publishToggle: "publishToggle", pageSettingsChange: "pageSettingsChange", applyAnimationToAll: "applyAnimationToAll", saveBlock: "saveBlock", globalElementsChange: "globalElementsChange" }, viewQueries: [{ propertyName: "previewCanvas", first: true, predicate: ["previewCanvas"], descendants: true }, { propertyName: "previewScrollRef", first: true, predicate: ["previewScroll"], descendants: true }, { propertyName: "lenisContentRef", first: true, predicate: ["lenisContent"], descendants: true }, { propertyName: "globalOverlayRef", first: true, predicate: ["globalOverlay"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"builder\">\n <header class=\"builder-header\">\n <div class=\"sidebar-switcher\">\n <button (click)=\"activeSidebar = 'pages'\" [class.active]=\"activeSidebar === 'pages'\" title=\"Pages\" aria-label=\"Pages\">\n <i class=\"ph-thin ph-browsers\"></i>\n </button>\n <button (click)=\"activeSidebar = 'components'\" [class.active]=\"activeSidebar === 'components'\" title=\"Components\" aria-label=\"Components\">\n <i class=\"ph-thin ph-cube\"></i>\n </button>\n <button (click)=\"activeSidebar = 'tree'\" [class.active]=\"activeSidebar === 'tree'\" title=\"Layers\" aria-label=\"Layers\">\n <i class=\"ph-thin ph-tree-structure\"></i>\n </button>\n <button (click)=\"activeSidebar = 'tokens'\" [class.active]=\"activeSidebar === 'tokens'\" title=\"Design Tokens\" aria-label=\"Design Tokens\">\n <i class=\"ph-thin ph-circles-three\"></i>\n </button>\n </div>\n\n <app-toolbar\n [activeMode]=\"activeMode\"\n [activeBreakpoint]=\"activeBreakpoint\"\n [breakpointCounts]=\"breakpointCounts\"\n [auditCount]=\"auditFindings.length\"\n [auditOpen]=\"auditOpen\"\n [activeZoom]=\"activeZoom\"\n [activeScreenWidth]=\"activeScreenWidth\"\n [isSaving]=\"isSaving\"\n [pageStatus]=\"pageStatus\"\n [canUndo]=\"canUndo\"\n [canRedo]=\"canRedo\"\n (modeChange)=\"handleToolbarModeChange($event)\"\n (breakpointChange)=\"handleToolbarBreakpointChange($event)\"\n (auditToggle)=\"toggleAudit()\"\n (zoomChange)=\"handleToolbarZoomChange($event)\"\n (screenWidthChange)=\"handleToolbarScreenWidthChange($event)\"\n (save)=\"save.emit()\"\n (preview)=\"preview.emit()\"\n (publishToggle)=\"publishToggle.emit()\"\n (undo)=\"undo.emit()\"\n (redo)=\"redo.emit()\">\n </app-toolbar>\n\n <div class=\"panel-switcher\">\n <button (click)=\"selectPanel(panelTypes.BINDINGS)\" [class.active]=\"activePanel === panelTypes.BINDINGS\" title=\"Bindings\">\n <i class=\"ph-thin ph-plugs-connected\"></i>\n </button>\n <button (click)=\"selectPanel(panelTypes.STYLES)\" [class.active]=\"activePanel === panelTypes.STYLES\" title=\"Styles\">\n <i class=\"ph-thin ph-paint-brush\"></i>\n </button>\n <button (click)=\"selectPanel(panelTypes.PAGE)\" [class.active]=\"activePanel === panelTypes.PAGE\" title=\"Page settings\" aria-label=\"Page settings\">\n <i class=\"ph-thin ph-gear-six\"></i>\n </button>\n <button (click)=\"selectPanel(panelTypes.INTERACTIONS)\" [class.active]=\"activePanel === panelTypes.INTERACTIONS\" title=\"Interactions\">\n <i class=\"ph-thin ph-lightning\"></i>\n </button>\n </div> \n </header>\n\n <div class=\"builder-main\" [class.panel-open]=\"isPanelOpen\">\n <aside class=\"sidebar\">\n <div *ngIf=\"activeSidebar === 'pages'\" class=\"sidebar-slot\">\n <ng-content select=\"[builderPages]\"></ng-content>\n </div>\n <div *ngIf=\"activeSidebar === 'components'\" class=\"sidebar-slot\">\n <ng-content select=\"[builderComponents]\"></ng-content>\n </div>\n <div *ngIf=\"activeSidebar === 'tokens'\" class=\"sidebar-slot\">\n <ng-content select=\"[builderTokens]\"></ng-content>\n </div>\n <app-layer-tree *ngIf=\"activeSidebar === 'tree'\"\n [layout]=\"layout\"\n [globalElements]=\"globalElements\"\n (nodeSelect)=\"onTreeNodeSelect($event)\"\n (nodeAction)=\"onTreeNodeAction($event)\"\n (nodeMove)=\"onTreeNodeMove()\"></app-layer-tree>\n </aside>\n\n <main #previewCanvas class=\"preview\"\n [class.grab-mode]=\"activeMode === builderModes.Pan\"\n [class.grabbing]=\"isPanning\"\n (click)=\"handleCanvasClick()\"\n (mousedown)=\"onBoardMouseDown($event)\"\n (mousemove)=\"onBoardMouseMove($event)\"\n (mouseup)=\"onBoardMouseUp()\"\n (mouseleave)=\"onBoardMouseUp()\">\n <app-overlay (toolbarAction)=\"onToolbarAction($event)\"></app-overlay>\n\n <!-- Element path \u2014 pinned to the PREVIEW VIEWPORT, not to the canvas frame. The frame\n pans and scales; a breadcrumb that tracked its edge would drift off-screen and\n shrink with zoom. Sits in the gutter above the frame (see $canvas-inset-block-start).\n\n \u26A0\uFE0F stopPropagation is REQUIRED, not defensive. This element lives inside .preview,\n whose (click) is handleCanvasClick() \u2014 \"you clicked empty canvas, drop the\n selection\". Without it, picking an ancestor crumb selects that node and then\n immediately bubbles into the canvas handler, which clears it: the selection and the\n layer-tree highlight both fall back to Body. Same reason .audit-dock stops its own. -->\n <app-breadcrumb-bar\n (click)=\"$event.stopPropagation()\"\n [path]=\"selectedPath\"\n (nodeSelect)=\"onCrumbSelect($event)\"\n (rootSelect)=\"onCrumbRootSelect()\"\n (nodePeek)=\"onCrumbPeek($event)\">\n </app-breadcrumb-bar>\n\n <!-- Responsive audit (A5) \u2014 floats over the canvas, right gutter. -->\n @if (auditOpen) {\n <div class=\"audit-dock\" (click)=\"$event.stopPropagation()\">\n <app-audit-panel\n [findings]=\"auditFindings\"\n [breakpointLabel]=\"auditBreakpointLabel\"\n [running]=\"auditRunning\"\n (select)=\"selectAuditNode($event)\"\n (fix)=\"applyAuditFix($event)\"\n (fixAll)=\"applyAllAuditFixes()\"\n (rerun)=\"runAudit()\"\n (closePanel)=\"toggleAudit()\"></app-audit-panel>\n </div>\n }\n\n <!-- Custom Lenis scrollbar \u2014 lives in .preview (not .preview-scroll) so it\n stays in the right gutter and never overlaps the canvas at large widths.\n No translateY counteract needed since it isn't inside the Lenis wrapper. -->\n <div class=\"canvas-scrollbar\"\n [class.visible]=\"isScrollbarVisible\">\n <div class=\"canvas-scrollbar-thumb\"\n [style.height.px]=\"scrollThumbHeight\"\n [style.top.px]=\"scrollThumbTop\">\n </div>\n </div>\n\n <!-- Global elements overlay \u2014 outside Lenis so position:fixed children\n stay pinned to the canvas viewport rather than scrolling with content.\n Shares viewportTransform so elements scale correctly at any zoom level.\n Height matches viewportHeight so position:fixed + inset:0 fills the\n simulated viewport correctly (CSS calc(100%) would give the wrong\n containing-block height and break full-screen fixed overlays). -->\n <div *ngIf=\"globalElements.length\"\n #globalOverlay\n class=\"global-elements-overlay\"\n [style.width.px]=\"viewportWidth\"\n [style.height.px]=\"canvasFrameHeight || viewportHeight\"\n [style.transform]=\"viewportTransform\">\n <ng-container *ngFor=\"let item of globalElementsBefore\">\n <ng-container [ioxRender]=\"item\"\n (onClick)=\"handleClick($event)\"\n (onMouseEnter)=\"handleMouseEnter($event)\"\n (onMouseLeave)=\"handleMouseLeave()\">\n </ng-container>\n </ng-container>\n <ng-container *ngFor=\"let item of globalElementsAfter\">\n <ng-container [ioxRender]=\"item\"\n (onClick)=\"handleClick($event)\"\n (onMouseEnter)=\"handleMouseEnter($event)\"\n (onMouseLeave)=\"handleMouseLeave()\">\n </ng-container>\n </ng-container>\n </div>\n\n <div class=\"preview-scroll\"\n #previewScroll\n [style.width.px]=\"viewportScaledWidth\"\n [class.pan-mode]=\"activeMode === builderModes.Pan\">\n\n <!-- Lenis content proxy: height = realContentHeight \u00D7 scale.\n Lenis scrolls against this value so scroll range is always in\n visual px \u2014 correct at any zoom level. -->\n <div class=\"preview-lenis-content\" #lenisContent\n [style.height.px]=\"scaledContentHeight\">\n\n <iox-page-component\n [style.width.px]=\"viewportWidth\"\n [style.height.px]=\"canvasFrameHeight || viewportHeight\"\n [style.transform]=\"viewportTransform\">\n\n <!-- ngStyle carries the page's own background/typography (pageSettings.style),\n compiled by the SAME function the engine applies to <body>. Inline wins over\n the #canvas-preview white default, which stays as the unset fallback. -->\n <div class=\"canvas-viewport\"\n id=\"canvas-preview\"\n [ngStyle]=\"pageStyleCss\"\n [style.min-height.px]=\"canvasMinHeight\">\n\n <!-- Empty page (B4): a starting point beats a blank canvas. Each starter is\n a responsive layout preset \u2014 ordinary nodes, editable afterwards. -->\n @if (isPageEmpty) {\n <div class=\"empty-canvas\" (click)=\"$event.stopPropagation()\">\n <h2 class=\"empty-title\">Start with a layout</h2>\n <p class=\"empty-sub\">Each one already adapts to tablet and phone. You can edit or take it apart afterwards.</p>\n <div class=\"empty-grid\">\n @for (starter of starterLayouts; track starter.id) {\n <button type=\"button\" class=\"empty-card\" (click)=\"startWithLayout(starter)\">\n <i [class]=\"starter.icon\" aria-hidden=\"true\"></i>\n <span class=\"empty-card-name\">{{ starter.name }}</span>\n <span class=\"empty-card-desc\">{{ starter.description }}</span>\n </button>\n }\n </div>\n <button type=\"button\" class=\"empty-link\" (click)=\"browseComponents()\">Or start from a single element</button>\n </div>\n }\n\n <!-- WRAPPER COLLAPSE (task 9c): top-level nodes render DIRECTLY into the\n canvas viewport \u2014 no .preview-node wrapper; iox-outer + drag move to the\n host (RenderDirective, via ioxDragSourceId). -->\n <ng-container *ngFor=\"let item of layout\"\n [ioxRender]=\"item\"\n [ioxDragSourceId]=\"'canvas-preview'\"\n (onClick)=\"handleClick($event)\"\n (onMouseEnter)=\"handleMouseEnter($event)\"\n (onMouseLeave)=\"handleMouseLeave()\">\n </ng-container>\n </div>\n </iox-page-component>\n </div>\n </div>\n </main>\n\n <ng-content select=\"[builderPanel]\"></ng-content>\n </div>\n\n <!-- Save as Reusable Block dialog -->\n @if (showSaveBlockDialog) {\n <div class=\"save-block-backdrop\" (click)=\"cancelSaveBlock()\"></div>\n <div class=\"save-block-dialog\" (click)=\"$event.stopPropagation()\">\n <h4 class=\"save-block-title\">Save as Reusable Block</h4>\n <input class=\"save-block-input\"\n type=\"text\"\n placeholder=\"Block name...\"\n [(ngModel)]=\"saveBlockName\"\n (keydown.enter)=\"confirmSaveBlock()\"\n (keydown.escape)=\"cancelSaveBlock()\"\n autofocus>\n <div class=\"save-block-actions\">\n <p-button size=\"small\" severity=\"secondary\" label=\"Cancel\" (click)=\"cancelSaveBlock()\"></p-button>\n <p-button size=\"small\" label=\"Save\" [disabled]=\"!saveBlockName.trim()\" (click)=\"confirmSaveBlock()\"></p-button>\n </div>\n </div>\n }\n</div>", styles: ["@charset \"UTF-8\";:host{display:flex;flex:1;min-height:0;overflow:hidden}.builder{display:flex;flex-direction:column;direction:ltr;width:100%;height:100%;min-height:0;border-radius:0;overflow:hidden;position:relative}.builder .builder-header{background:var(--p-surface-0);padding:.375rem .75rem;border-bottom:1px solid var(--p-surface-200);display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:.5rem;flex-shrink:0}.builder .builder-header .header-back{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:6px;cursor:pointer;color:var(--p-text-muted-color);font-size:16px;transition:background .15s ease-out;margin-inline-end:.25rem}.builder .builder-header .header-back:hover{background:var(--p-surface-50);color:var(--p-text-color)}.builder .builder-header .header-page-name{flex:1;text-align:center;font-size:.8rem;font-weight:500;color:var(--p-text-muted-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-inline:1rem}.builder .sidebar-switcher,.builder .panel-switcher{display:flex;gap:.25rem}.builder .sidebar-switcher button,.builder .panel-switcher button{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:6px;border:none;background:transparent;color:var(--p-text-muted-color);cursor:pointer;font-size:1rem;transition:background .15s ease-out,color .15s ease-out}.builder .sidebar-switcher button i,.builder .panel-switcher button i{pointer-events:none}.builder .sidebar-switcher button:hover,.builder .panel-switcher button:hover{background:var(--p-surface-50);color:var(--p-text-color)}.builder .sidebar-switcher button.active,.builder .panel-switcher button.active{background:#cb9090;color:#fff}.builder .panel-switcher{justify-self:end}.builder .builder-main{display:flex;flex:1 1 0;min-height:0;position:relative;overflow:hidden}.builder .sidebar{width:260px;min-width:260px;background:var(--p-surface-0);border-inline-end:1px solid var(--p-surface-200);overflow-y:auto;overflow-x:hidden;flex-shrink:0}.builder .preview{flex:1 1 0;min-width:0;min-height:0;position:relative;overflow:hidden}.builder .preview.grab-mode{cursor:grab}.builder .preview.grab-mode iox-page-component{pointer-events:none}.builder .preview.grabbing{cursor:grabbing}.builder .canvas-scrollbar{position:absolute;right:4px;top:46px;bottom:20px;width:6px;z-index:20;opacity:0;transition:opacity .2s ease;pointer-events:none}.builder .canvas-scrollbar.visible{opacity:1}.builder .canvas-scrollbar-thumb{position:absolute;left:0;width:100%;background:#00000059;border-radius:3px;transition:top .05s linear}.builder .preview-scroll{position:absolute;inset:46px auto 20px;inset-inline-start:50%;transform:translate(-50%);max-width:calc(100% - 40px);height:calc(100% - 66px);overflow:hidden}.builder .preview-lenis-content{position:relative;width:100%;overflow:hidden;contain:paint}.builder iox-page-component{position:absolute!important;top:0;bottom:auto!important;right:auto!important;left:50%;transform-origin:top center;overflow:visible!important;container:iox-canvas/inline-size;box-shadow:0 1px 4px #00000014,0 4px 16px #0000000a;transition:width .25s ease,transform .25s ease}.builder iox-page-component ::ng-deep .iox-page-wrapper{height:auto!important;overflow:visible!important}.builder #canvas-preview{background:#fff}.builder .empty-canvas{max-inline-size:560px;margin:0 auto;padding:48px 24px;text-align:center;color:#4b5563}.builder .empty-title{margin:0;font-size:18px;font-weight:600;color:#111827}.builder .empty-sub{margin:6px 0 20px;font-size:12px;line-height:1.5;color:#6b7280}.builder .empty-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.builder .empty-card{display:flex;flex-direction:column;align-items:center;gap:4px;padding:14px 10px;border:1px solid #e5e7eb;border-radius:10px;background:#fff;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}.builder .empty-card:hover{border-color:#cb9090;box-shadow:0 2px 10px #0000000f}.builder .empty-card:focus-visible{outline:2px solid #cb9090;outline-offset:2px}.builder .empty-card i{font-size:20px;color:#a05c5c}.builder .empty-card-name{font-size:11.5px;font-weight:600;color:#111827}.builder .empty-card-desc{font-size:9.5px;line-height:1.35;color:#6b7280}.builder .empty-link{margin-block-start:16px;padding:0;border:none;background:none;font-size:11px;color:#a05c5c;cursor:pointer}.builder .empty-link:hover{text-decoration:underline}.builder .empty-link:focus-visible{outline:2px solid #cb9090;outline-offset:2px}.builder app-breadcrumb-bar{position:absolute;inset-block-start:12px;inset-inline-start:20px;inset-inline-end:56px;z-index:20;pointer-events:none}.builder .audit-dock{position:absolute;inset-block-start:46px;inset-inline-end:16px;z-index:20}.builder .global-elements-overlay{position:absolute;top:46px;left:50%;transform-origin:top center;pointer-events:none;z-index:9;overflow:hidden;container:iox-canvas/inline-size}.builder .global-elements-overlay ::ng-deep>*{pointer-events:auto}.builder .preview-node.is-selected{cursor:grab}.builder .empty-state{min-height:240px;border:1px dashed var(--p-surface-200);border-radius:10px;display:flex;align-items:center;justify-content:center;color:var(--p-text-muted-color);text-align:center;padding:1rem}.save-block-backdrop{position:fixed;inset:0;z-index:1000;background:#00000040}.save-block-dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1001;background:#fff;border-radius:8px;box-shadow:0 8px 32px #0000002e;padding:24px;width:320px}.save-block-dialog .save-block-title{margin:0 0 16px;font-size:14px;font-weight:600;color:var(--p-text-color, #333)}.save-block-dialog .save-block-input{width:100%;padding:8px 10px;border:1px solid var(--p-surface-300, #d1d5db);border-radius:6px;font-size:13px;outline:none;box-sizing:border-box;margin-bottom:16px}.save-block-dialog .save-block-input:focus{border-color:#cb9090;box-shadow:0 0 0 2px #cb909033}.save-block-dialog .save-block-actions{display:flex;justify-content:flex-end;gap:8px}::ng-deep .moveable-control-box.iox-moveable-silent{z-index:1000!important}::ng-deep .moveable-control-box.iox-moveable-silent .moveable-line,::ng-deep .moveable-control-box.iox-moveable-silent .moveable-rotation,::ng-deep .moveable-control-box.iox-moveable-silent .moveable-rotation-line{display:none!important}::ng-deep .moveable-control-box.iox-moveable-silent .moveable-control{display:block!important;width:10px!important;height:10px!important;margin-top:-5px!important;margin-left:-5px!important;background:#fff!important;border:1.5px solid #cb9090!important;border-radius:2px!important;box-shadow:0 1px 3px #0003!important}\n"], dependencies: [{ 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.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i16.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i16.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i16.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i17.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$2.IoxPageComponent, selector: "iox-page-component", inputs: ["class"], outputs: ["scrollEvent"] }, { kind: "directive", type: RenderDirective, selector: "[ioxRender]", inputs: ["ioxRender", "ioxDragSourceId"], outputs: ["onClick", "onMouseEnter", "onMouseLeave"] }, { kind: "component", type: OverlayComponent, selector: "app-overlay", outputs: ["toolbarAction"] }, { kind: "component", type: ToolbarComponent, selector: "app-toolbar", inputs: ["activeMode", "activeBreakpoint", "breakpointCounts", "auditCount", "auditOpen", "activeZoom", "activeScreenWidth", "canUndo", "canRedo", "isSaving", "pageStatus"], outputs: ["modeChange", "breakpointChange", "auditToggle", "zoomChange", "screenWidthChange", "undo", "redo", "save", "preview", "publishToggle"] }, { kind: "component", type: LayerTreeComponent, selector: "app-layer-tree", inputs: ["layout", "globalElements"], outputs: ["nodeSelect", "nodeAction", "nodeMove"] }, { kind: "component", type: BreadcrumbBarComponent, selector: "app-breadcrumb-bar", inputs: ["path"], outputs: ["nodeSelect", "rootSelect", "nodePeek"] }, { kind: "component", type: AuditPanelComponent, selector: "app-audit-panel", inputs: ["findings", "breakpointLabel", "running"], outputs: ["select", "fix", "fixAll", "rerun", "closePanel"] }] }); }
|
|
7211
7244
|
}
|
|
7212
7245
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderComponent, decorators: [{
|
|
7213
7246
|
type: Component,
|
|
@@ -8274,6 +8307,166 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
8274
8307
|
type: Output
|
|
8275
8308
|
}] } });
|
|
8276
8309
|
|
|
8310
|
+
/**
|
|
8311
|
+
* The Dialog's CANVAS twin (actions plan A1b / boards A4–A5). Two render strategies, one model:
|
|
8312
|
+
* the live site uses a real `<dialog>` (top layer); here the overlay is `position: fixed`, which
|
|
8313
|
+
* a transformed ancestor CONTAINS — so it fills the page frame, not the admin viewport, at every
|
|
8314
|
+
* zoom. Closed it renders as a compact chip in flow (A4's "closed later? reopen from the chip"),
|
|
8315
|
+
* and a freshly dropped EMPTY dialog opens itself — you land designing it, not hunting it.
|
|
8316
|
+
* Open/close/toggle actions reach it through the instance registry, same as Swiper's methods.
|
|
8317
|
+
*/
|
|
8318
|
+
class BuilderDialogComponent {
|
|
8319
|
+
constructor(dragEngine, instanceRegistry, cdr) {
|
|
8320
|
+
this.dragEngine = dragEngine;
|
|
8321
|
+
this.instanceRegistry = instanceRegistry;
|
|
8322
|
+
this.cdr = cdr;
|
|
8323
|
+
this.children = [];
|
|
8324
|
+
this.style = {};
|
|
8325
|
+
this.nodeId = '';
|
|
8326
|
+
this.dropListId = '';
|
|
8327
|
+
this.closeOnBackdrop = true;
|
|
8328
|
+
this.showCloseButton = true;
|
|
8329
|
+
this.childClick = new EventEmitter();
|
|
8330
|
+
this.childMouseEnter = new EventEmitter();
|
|
8331
|
+
this.childMouseLeave = new EventEmitter();
|
|
8332
|
+
/** Canvas-only visibility. Never serialised; the live site always starts closed. */
|
|
8333
|
+
this.designOpen = false;
|
|
8334
|
+
}
|
|
8335
|
+
ngOnInit() {
|
|
8336
|
+
// A freshly dropped EMPTY dialog opens itself — "lands open" (board A4).
|
|
8337
|
+
this.designOpen = this.children.length === 0;
|
|
8338
|
+
// Open/close/toggle actions (and A1c's panel) reach the canvas twin through here.
|
|
8339
|
+
this.instanceRegistry.register(this.nodeId, {
|
|
8340
|
+
open: () => { this.designOpen = true; this.cdr.markForCheck(); },
|
|
8341
|
+
close: () => { this.designOpen = false; this.cdr.markForCheck(); },
|
|
8342
|
+
toggle: () => { this.designOpen = !this.designOpen; this.cdr.markForCheck(); },
|
|
8343
|
+
isOpen: () => this.designOpen,
|
|
8344
|
+
});
|
|
8345
|
+
}
|
|
8346
|
+
ngOnDestroy() {
|
|
8347
|
+
this.instanceRegistry.unregister(this.nodeId);
|
|
8348
|
+
}
|
|
8349
|
+
onBackdrop() {
|
|
8350
|
+
if (this.closeOnBackdrop !== false && this.closeOnBackdrop !== 'false')
|
|
8351
|
+
this.designOpen = false;
|
|
8352
|
+
}
|
|
8353
|
+
onDrop(event) {
|
|
8354
|
+
this.dragEngine.handleDrop(this.children, event, this.dropListId, this.cdr);
|
|
8355
|
+
}
|
|
8356
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderDialogComponent, deps: [{ token: DragEngineService }, { token: i2$2.ComponentInstanceRegistryService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8357
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.31", type: BuilderDialogComponent, isStandalone: false, selector: "app-builder-dialog", inputs: { children: "children", style: "style", nodeId: "nodeId", dropListId: "dropListId", closeOnBackdrop: "closeOnBackdrop", showCloseButton: "showCloseButton" }, outputs: { childClick: "childClick", childMouseEnter: "childMouseEnter", childMouseLeave: "childMouseLeave" }, ngImport: i0, template: `
|
|
8358
|
+
<div *ngIf="!designOpen"
|
|
8359
|
+
class="dialog-chip"
|
|
8360
|
+
role="button"
|
|
8361
|
+
tabindex="0"
|
|
8362
|
+
[attr.aria-label]="'Open dialog for editing'"
|
|
8363
|
+
(click)="designOpen = true"
|
|
8364
|
+
(keydown.enter)="designOpen = true">
|
|
8365
|
+
<i class="ph-thin ph-browser"></i>
|
|
8366
|
+
<span class="dialog-chip-label">Dialog</span>
|
|
8367
|
+
<i class="ph-thin ph-eye dialog-chip-eye"></i>
|
|
8368
|
+
</div>
|
|
8369
|
+
|
|
8370
|
+
<div *ngIf="designOpen" class="dialog-stage">
|
|
8371
|
+
<div class="dialog-backdrop" (click)="onBackdrop()"></div>
|
|
8372
|
+
<div [ngStyle]="style"
|
|
8373
|
+
[ngClass]="'iox-node-' + nodeId"
|
|
8374
|
+
class="dialog-surface"
|
|
8375
|
+
ioxDropzone
|
|
8376
|
+
[ioxDropzoneId]="dropListId"
|
|
8377
|
+
[ioxDropzoneData]="children"
|
|
8378
|
+
(ioxDrop)="onDrop($event)">
|
|
8379
|
+
<button *ngIf="showCloseButton"
|
|
8380
|
+
type="button"
|
|
8381
|
+
class="dialog-close"
|
|
8382
|
+
aria-label="Close dialog"
|
|
8383
|
+
(click)="designOpen = false">
|
|
8384
|
+
<i class="ph-thin ph-x"></i>
|
|
8385
|
+
</button>
|
|
8386
|
+
|
|
8387
|
+
<div *ngIf="!children.length" class="dialog-placeholder">
|
|
8388
|
+
<i class="ph-thin ph-browser"></i>
|
|
8389
|
+
<span>Drop components here</span>
|
|
8390
|
+
</div>
|
|
8391
|
+
|
|
8392
|
+
<ng-container *ngFor="let child of children"
|
|
8393
|
+
[ioxRender]="child"
|
|
8394
|
+
[ioxDragSourceId]="dropListId"
|
|
8395
|
+
(onClick)="childClick.emit($event)"
|
|
8396
|
+
(onMouseEnter)="childMouseEnter.emit($event)"
|
|
8397
|
+
(onMouseLeave)="childMouseLeave.emit()">
|
|
8398
|
+
</ng-container>
|
|
8399
|
+
</div>
|
|
8400
|
+
</div>
|
|
8401
|
+
`, isInline: true, styles: [".dialog-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border:1.5px dashed rgba(203,144,144,.6);border-radius:999px;color:#a05c5c;font-size:12px;cursor:pointer;-webkit-user-select:none;user-select:none;background:#cb90900f}.dialog-chip i{font-size:14px}.dialog-chip-eye{opacity:.7}.dialog-stage{position:fixed;inset:0;z-index:50}.dialog-backdrop{position:absolute;inset:0;background:#0f172a73}.dialog-surface{position:absolute;inset-inline-start:50%;top:50%;transform:translate(-50%,-50%);box-sizing:border-box;max-width:calc(100% - 48px);max-height:calc(100% - 48px);overflow:auto}:host-context([dir=\"rtl\"]) .dialog-surface{transform:translate(50%,-50%)}.dialog-close{position:absolute;inset-inline-end:10px;top:10px;width:26px;height:26px;border:none;border-radius:999px;background:#0f172a0f;color:inherit;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.dialog-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:90px;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px}.dialog-placeholder i{font-size:18px}\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.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: RenderDirective, selector: "[ioxRender]", inputs: ["ioxRender", "ioxDragSourceId"], outputs: ["onClick", "onMouseEnter", "onMouseLeave"] }, { kind: "directive", type: IoxDropzoneDirective, selector: "[ioxDropzone]", inputs: ["ioxDropzoneId", "ioxDropzoneData", "ioxDropzonePostDrop"], outputs: ["ioxDrop"] }] }); }
|
|
8402
|
+
}
|
|
8403
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderDialogComponent, decorators: [{
|
|
8404
|
+
type: Component,
|
|
8405
|
+
args: [{ selector: 'app-builder-dialog', template: `
|
|
8406
|
+
<div *ngIf="!designOpen"
|
|
8407
|
+
class="dialog-chip"
|
|
8408
|
+
role="button"
|
|
8409
|
+
tabindex="0"
|
|
8410
|
+
[attr.aria-label]="'Open dialog for editing'"
|
|
8411
|
+
(click)="designOpen = true"
|
|
8412
|
+
(keydown.enter)="designOpen = true">
|
|
8413
|
+
<i class="ph-thin ph-browser"></i>
|
|
8414
|
+
<span class="dialog-chip-label">Dialog</span>
|
|
8415
|
+
<i class="ph-thin ph-eye dialog-chip-eye"></i>
|
|
8416
|
+
</div>
|
|
8417
|
+
|
|
8418
|
+
<div *ngIf="designOpen" class="dialog-stage">
|
|
8419
|
+
<div class="dialog-backdrop" (click)="onBackdrop()"></div>
|
|
8420
|
+
<div [ngStyle]="style"
|
|
8421
|
+
[ngClass]="'iox-node-' + nodeId"
|
|
8422
|
+
class="dialog-surface"
|
|
8423
|
+
ioxDropzone
|
|
8424
|
+
[ioxDropzoneId]="dropListId"
|
|
8425
|
+
[ioxDropzoneData]="children"
|
|
8426
|
+
(ioxDrop)="onDrop($event)">
|
|
8427
|
+
<button *ngIf="showCloseButton"
|
|
8428
|
+
type="button"
|
|
8429
|
+
class="dialog-close"
|
|
8430
|
+
aria-label="Close dialog"
|
|
8431
|
+
(click)="designOpen = false">
|
|
8432
|
+
<i class="ph-thin ph-x"></i>
|
|
8433
|
+
</button>
|
|
8434
|
+
|
|
8435
|
+
<div *ngIf="!children.length" class="dialog-placeholder">
|
|
8436
|
+
<i class="ph-thin ph-browser"></i>
|
|
8437
|
+
<span>Drop components here</span>
|
|
8438
|
+
</div>
|
|
8439
|
+
|
|
8440
|
+
<ng-container *ngFor="let child of children"
|
|
8441
|
+
[ioxRender]="child"
|
|
8442
|
+
[ioxDragSourceId]="dropListId"
|
|
8443
|
+
(onClick)="childClick.emit($event)"
|
|
8444
|
+
(onMouseEnter)="childMouseEnter.emit($event)"
|
|
8445
|
+
(onMouseLeave)="childMouseLeave.emit()">
|
|
8446
|
+
</ng-container>
|
|
8447
|
+
</div>
|
|
8448
|
+
</div>
|
|
8449
|
+
`, standalone: false, styles: [".dialog-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border:1.5px dashed rgba(203,144,144,.6);border-radius:999px;color:#a05c5c;font-size:12px;cursor:pointer;-webkit-user-select:none;user-select:none;background:#cb90900f}.dialog-chip i{font-size:14px}.dialog-chip-eye{opacity:.7}.dialog-stage{position:fixed;inset:0;z-index:50}.dialog-backdrop{position:absolute;inset:0;background:#0f172a73}.dialog-surface{position:absolute;inset-inline-start:50%;top:50%;transform:translate(-50%,-50%);box-sizing:border-box;max-width:calc(100% - 48px);max-height:calc(100% - 48px);overflow:auto}:host-context([dir=\"rtl\"]) .dialog-surface{transform:translate(50%,-50%)}.dialog-close{position:absolute;inset-inline-end:10px;top:10px;width:26px;height:26px;border:none;border-radius:999px;background:#0f172a0f;color:inherit;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.dialog-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:90px;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px}.dialog-placeholder i{font-size:18px}\n"] }]
|
|
8450
|
+
}], ctorParameters: () => [{ type: DragEngineService }, { type: i2$2.ComponentInstanceRegistryService }, { type: i0.ChangeDetectorRef }], propDecorators: { children: [{
|
|
8451
|
+
type: Input
|
|
8452
|
+
}], style: [{
|
|
8453
|
+
type: Input
|
|
8454
|
+
}], nodeId: [{
|
|
8455
|
+
type: Input
|
|
8456
|
+
}], dropListId: [{
|
|
8457
|
+
type: Input
|
|
8458
|
+
}], closeOnBackdrop: [{
|
|
8459
|
+
type: Input
|
|
8460
|
+
}], showCloseButton: [{
|
|
8461
|
+
type: Input
|
|
8462
|
+
}], childClick: [{
|
|
8463
|
+
type: Output
|
|
8464
|
+
}], childMouseEnter: [{
|
|
8465
|
+
type: Output
|
|
8466
|
+
}], childMouseLeave: [{
|
|
8467
|
+
type: Output
|
|
8468
|
+
}] } });
|
|
8469
|
+
|
|
8277
8470
|
class SliderContainerComponent {
|
|
8278
8471
|
set style(v) {
|
|
8279
8472
|
if (v === this._style)
|
|
@@ -9315,6 +9508,7 @@ const DECLARATIONS = [
|
|
|
9315
9508
|
BuilderLinkedContainerComponent,
|
|
9316
9509
|
BuilderRepeaterComponent,
|
|
9317
9510
|
BuilderButtonBlockComponent,
|
|
9511
|
+
BuilderDialogComponent,
|
|
9318
9512
|
SliderContainerComponent,
|
|
9319
9513
|
SliderSlideComponent,
|
|
9320
9514
|
PanelComponent,
|
|
@@ -9336,6 +9530,7 @@ class IoxBuilderModule {
|
|
|
9336
9530
|
BuilderLinkedContainerComponent,
|
|
9337
9531
|
BuilderRepeaterComponent,
|
|
9338
9532
|
BuilderButtonBlockComponent,
|
|
9533
|
+
BuilderDialogComponent,
|
|
9339
9534
|
SliderContainerComponent,
|
|
9340
9535
|
SliderSlideComponent,
|
|
9341
9536
|
PanelComponent,
|
|
@@ -9377,6 +9572,7 @@ class IoxBuilderModule {
|
|
|
9377
9572
|
BuilderLinkedContainerComponent,
|
|
9378
9573
|
BuilderRepeaterComponent,
|
|
9379
9574
|
BuilderButtonBlockComponent,
|
|
9575
|
+
BuilderDialogComponent,
|
|
9380
9576
|
SliderContainerComponent,
|
|
9381
9577
|
SliderSlideComponent,
|
|
9382
9578
|
PanelComponent,
|
|
@@ -9483,6 +9679,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
9483
9679
|
BuilderLinkedContainerComponent,
|
|
9484
9680
|
BuilderRepeaterComponent,
|
|
9485
9681
|
BuilderButtonBlockComponent,
|
|
9682
|
+
BuilderDialogComponent,
|
|
9486
9683
|
SliderContainerComponent,
|
|
9487
9684
|
SliderSlideComponent,
|
|
9488
9685
|
PanelComponent,
|
|
@@ -9669,6 +9866,36 @@ function setTrait(node, name, value) {
|
|
|
9669
9866
|
trait.default = value;
|
|
9670
9867
|
}
|
|
9671
9868
|
|
|
9869
|
+
/**
|
|
9870
|
+
* Dialog (actions plan A1b) — an ordinary container whose children are normal nodes, rendered
|
|
9871
|
+
* on the live site as a real `<dialog>` (top layer, free focus trap/Esc) and in the CANVAS as a
|
|
9872
|
+
* fixed-position overlay contained by the transformed frame (a transform is a containing block
|
|
9873
|
+
* for fixed descendants — the deliberate two-strategy split, see actions plan §6a).
|
|
9874
|
+
* Ships CLOSED on the live site always; opened only by the dialog actions.
|
|
9875
|
+
*/
|
|
9876
|
+
class DialogComponentConfig extends ComponentConfig {
|
|
9877
|
+
constructor() {
|
|
9878
|
+
super('Dialog', 'app-builder-dialog', 'ph-thin ph-browser', 'Overlay');
|
|
9879
|
+
this.children = [];
|
|
9880
|
+
this.inputs = {
|
|
9881
|
+
closeOnBackdrop: 'checkbox',
|
|
9882
|
+
showCloseButton: 'checkbox',
|
|
9883
|
+
};
|
|
9884
|
+
this.traits = [
|
|
9885
|
+
new TraitConfig('closeOnBackdrop', 'Close on backdrop', TraitInputType.Checkbox, undefined, true),
|
|
9886
|
+
new TraitConfig('showCloseButton', 'Close button', TraitInputType.Checkbox, undefined, true),
|
|
9887
|
+
];
|
|
9888
|
+
this.styleTraits = buildFullStyleTraits();
|
|
9889
|
+
this.applyStyleDefaults({
|
|
9890
|
+
width: '480px',
|
|
9891
|
+
backgroundColor: '#ffffff',
|
|
9892
|
+
borderRadius: '12px',
|
|
9893
|
+
padding: '24px',
|
|
9894
|
+
boxShadow: '0 18px 40px rgba(0, 0, 0, 0.22)',
|
|
9895
|
+
});
|
|
9896
|
+
}
|
|
9897
|
+
}
|
|
9898
|
+
|
|
9672
9899
|
class BuilderButtonComponentConfig extends ComponentConfig {
|
|
9673
9900
|
constructor() {
|
|
9674
9901
|
super('Button', 'app-builder-button', 'ph-thin ph-cursor-click', 'Basic');
|
|
@@ -10485,5 +10712,5 @@ class BuilderSpacerComponentConfig extends ComponentConfig {
|
|
|
10485
10712
|
* Generated bundle index. Do not edit.
|
|
10486
10713
|
*/
|
|
10487
10714
|
|
|
10488
|
-
export { ACTION_TYPE_OPTIONS, AuditCode, AuditPanelComponent, AuditSeverity, BODY_CRUMB_LABEL, BREAKPOINT_PRESENTATION, BUILDER_CANVAS_CONTAINER, BUILDER_CHROME_EN, BackgroundGroupStyleConfig, BorderGroupStyleConfig, BreadcrumbBarComponent, BuilderButtonBlockComponent, BuilderButtonComponentConfig, BuilderClipboardService, BuilderComponent, BuilderContainerComponent, BuilderContainerComponentConfig, BuilderDataSourceService, BuilderDividerComponentConfig, BuilderHeadingComponentConfig, BuilderHistoryService, BuilderIconComponentConfig, BuilderImageComponentConfig, BuilderLinkComponentConfig, BuilderLinkedContainerComponent, BuilderLinkedContainerConfig, BuilderListComponentConfig, BuilderListItemComponentConfig, BuilderMode, BuilderRepeaterComponent, BuilderSpacerComponentConfig, ButtonBlockComponentConfig, CardComponentConfig, ChildLayoutGroupStyleConfig, ComponentConfig, ComponentRegistryService, DEFAULT_ESSENTIAL_TRAITS, DRAG_HANDLE_ATTR, DataSourceRegistryService, DataSourceType, DimensionsGroupStyleConfig, DragEngineService, EASING_OPTIONS$1 as EASING_OPTIONS, ESSENTIAL_TRAITS_BY_TYPE, EffectsGroupStyleConfig, FIELD_PARTS, FORM_PRESETS, FORM_TYPE, FieldComponentConfig, FieldGroupComponentConfig, FormComponentConfig, FormErrorComponentConfig, FormStateService, FormSuccessComponentConfig, GalleryConfig, GroupStyleConfig, INTERACTION_STATES, INVERSE_ACTION, IOX_BUILDER_LABELS, IOX_DATA_SOURCE_ENDPOINTS, IOX_FONT_MANAGER, InteractionEngineService, InteractionPresetRegistryService, IoxBuilderModule, IoxDraggableDirective, IoxDropzoneDirective, LAYOUT_PRESETS, LayerTreeComponent, LayoutGroupStyleConfig, ListGroupStyleConfig, NodeAction, OverlayComponent, OverlayService, PanelChildComponent, PanelComponent, PanelEventService, PanelEventTypes, PanelTypes, PositionGroupStyleConfig, PresetRegistryService, RELATIONAL_STATES, RELATIONAL_STATE_BASE, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, SCREEN_WIDTH_OPTIONS, STRUCTURAL_STATES, SUPPORTED_STATES, SectionComponent, SectionComponentConfig, SizeGroupStyleConfig, SliderContainerComponent, SliderContainerConfig, SliderSlideComponent, SliderSlideConfig, SpacingGroupStyleConfig, StyleCategory, StyleRegistryService, TraitConfig as StyleTraitConfig, SubmitButtonComponentConfig, SymbolRegistryService, TARGETED_STATES, TARGETED_STATE_BASE, TRIGGER_OPTIONS, TextBlockComponentConfig, ToolbarAction, ToolbarComponent, TraitConfig, TraitInputType, TypographyGroupStyleConfig, UNITS_ALL, UNITS_DEG, UNITS_FIXED, UNITS_NO_VW, VALIDATION_STATES, VALIDATION_STATE_CLASS, ViewportService, ZOOM_OPTIONS, arrayItemSchemaFields, arraySchemaFields, auditNodes, buildFormPreset, buildFullStyleTraits, buildLayoutPreset, buildPresetStyleTraits, canFluidise, collapseColumnsProps, columnCountOf, defaultBuilderLabels, defaultPageSettings, dropTargetLabel, essentialTraitsFor, findNodeLocation, findParentOf, flattenSchemaFields, fluidiseProps, generateNodeId, isHiddenAt, matchesControlSearch, nearestFormNode, nodeAncestorPath, nodeAncestorPathInEither, reorderProps, resolveInsertTarget, resolveTraitControllerType, resolveTraitOptions, setStyleTrait, stackChildrenProps, summarise, visibilityProps, wrapNode };
|
|
10715
|
+
export { ACTION_TYPE_OPTIONS, AuditCode, AuditPanelComponent, AuditSeverity, BODY_CRUMB_LABEL, BREAKPOINT_PRESENTATION, BUILDER_CANVAS_CONTAINER, BUILDER_CHROME_EN, BackgroundGroupStyleConfig, BorderGroupStyleConfig, BreadcrumbBarComponent, BuilderButtonBlockComponent, BuilderButtonComponentConfig, BuilderClipboardService, BuilderComponent, BuilderContainerComponent, BuilderContainerComponentConfig, BuilderDataSourceService, BuilderDialogComponent, BuilderDividerComponentConfig, BuilderHeadingComponentConfig, BuilderHistoryService, BuilderIconComponentConfig, BuilderImageComponentConfig, BuilderLinkComponentConfig, BuilderLinkedContainerComponent, BuilderLinkedContainerConfig, BuilderListComponentConfig, BuilderListItemComponentConfig, BuilderMode, BuilderRepeaterComponent, BuilderSpacerComponentConfig, ButtonBlockComponentConfig, CardComponentConfig, ChildLayoutGroupStyleConfig, ComponentConfig, ComponentRegistryService, DEFAULT_ESSENTIAL_TRAITS, DRAG_HANDLE_ATTR, DataSourceRegistryService, DataSourceType, DialogComponentConfig, DimensionsGroupStyleConfig, DragEngineService, EASING_OPTIONS$1 as EASING_OPTIONS, ESSENTIAL_TRAITS_BY_TYPE, EffectsGroupStyleConfig, FIELD_PARTS, FORM_PRESETS, FORM_TYPE, FieldComponentConfig, FieldGroupComponentConfig, FormComponentConfig, FormErrorComponentConfig, FormStateService, FormSuccessComponentConfig, GalleryConfig, GroupStyleConfig, INTERACTION_STATES, INVERSE_ACTION, IOX_BUILDER_LABELS, IOX_DATA_SOURCE_ENDPOINTS, IOX_FONT_MANAGER, InteractionEngineService, InteractionPresetRegistryService, IoxBuilderModule, IoxDraggableDirective, IoxDropzoneDirective, LAYOUT_PRESETS, LayerTreeComponent, LayoutGroupStyleConfig, ListGroupStyleConfig, NodeAction, OverlayComponent, OverlayService, PanelChildComponent, PanelComponent, PanelEventService, PanelEventTypes, PanelTypes, PositionGroupStyleConfig, PresetRegistryService, RELATIONAL_STATES, RELATIONAL_STATE_BASE, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, SCREEN_WIDTH_OPTIONS, STRUCTURAL_STATES, SUPPORTED_STATES, SectionComponent, SectionComponentConfig, SizeGroupStyleConfig, SliderContainerComponent, SliderContainerConfig, SliderSlideComponent, SliderSlideConfig, SpacingGroupStyleConfig, StyleCategory, StyleRegistryService, TraitConfig as StyleTraitConfig, SubmitButtonComponentConfig, SymbolRegistryService, TARGETED_STATES, TARGETED_STATE_BASE, TRIGGER_OPTIONS, TextBlockComponentConfig, ToolbarAction, ToolbarComponent, TraitConfig, TraitInputType, TypographyGroupStyleConfig, UNITS_ALL, UNITS_DEG, UNITS_FIXED, UNITS_NO_VW, VALIDATION_STATES, VALIDATION_STATE_CLASS, ViewportService, ZOOM_OPTIONS, arrayItemSchemaFields, arraySchemaFields, auditNodes, buildFormPreset, buildFullStyleTraits, buildLayoutPreset, buildPresetStyleTraits, canFluidise, collapseColumnsProps, columnCountOf, defaultBuilderLabels, defaultPageSettings, dropTargetLabel, essentialTraitsFor, findNodeLocation, findParentOf, flattenSchemaFields, fluidiseProps, generateNodeId, isHiddenAt, matchesControlSearch, nearestFormNode, nodeAncestorPath, nodeAncestorPathInEither, reorderProps, resolveInsertTarget, resolveTraitControllerType, resolveTraitOptions, setStyleTrait, stackChildrenProps, summarise, visibilityProps, wrapNode };
|
|
10489
10716
|
//# sourceMappingURL=vectoriox-iox-builder.mjs.map
|