@vectoriox/iox-builder 2.10.2 → 2.10.4
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.
|
@@ -17,7 +17,7 @@ import { SelectModule } from 'primeng/select';
|
|
|
17
17
|
import { TooltipModule } from 'primeng/tooltip';
|
|
18
18
|
import { DialogModule } from 'primeng/dialog';
|
|
19
19
|
import * as i16 from '@vectoriox/iox-ui';
|
|
20
|
-
import { DEFAULT_WIDTH_BY_TYPE, ComponentInstanceRegistryService, buildTargetedStateSelector, compileDeclarations, composeVirtualTraits, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule } from '@vectoriox/iox-ui';
|
|
20
|
+
import { DEFAULT_WIDTH_BY_TYPE, ComponentInstanceRegistryService, buildTargetedStateSelector, compileDeclarations, safeSetInput, composeVirtualTraits, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule } from '@vectoriox/iox-ui';
|
|
21
21
|
export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTraits } from '@vectoriox/iox-ui';
|
|
22
22
|
import Lenis from 'lenis';
|
|
23
23
|
import { Subject, BehaviorSubject, of, forkJoin } from 'rxjs';
|
|
@@ -677,6 +677,65 @@ function arrayItemSchemaFields(properties, arrayPath) {
|
|
|
677
677
|
return { fields: [], isPrimitive: true };
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
+
const freshId = () => Math.random().toString(36).substr(2, 9);
|
|
681
|
+
/**
|
|
682
|
+
* Assign fresh ids to a cloned ComponentNode subtree AND remap intra-subtree references to the
|
|
683
|
+
* new ids. Used by every author-time clone path (duplicate, paste, block/external drop) so a copied
|
|
684
|
+
* structure stays self-consistent.
|
|
685
|
+
*
|
|
686
|
+
* Absolute node-id references that break under duplication if left unmapped:
|
|
687
|
+
* - `stateTriggers[state]` — the trigger-hover target (see style-engine.md → Targeted states)
|
|
688
|
+
* - interaction `action.target` / `reverseActions.target`
|
|
689
|
+
* A reference pointing OUTSIDE the cloned subtree (id not in the map) is left untouched — the copy
|
|
690
|
+
* intentionally still points at the external node.
|
|
691
|
+
*
|
|
692
|
+
* `styleId` strategy:
|
|
693
|
+
* - `'clear'` (default) — drop styleId so the clone OWNS its own CSS rule (independent copy).
|
|
694
|
+
* - `'regenerate'` — keep a styleId but give it a fresh value (legacy builder.component path).
|
|
695
|
+
*/
|
|
696
|
+
function regenerateNodeIds(root, opts = {}) {
|
|
697
|
+
const idMap = new Map();
|
|
698
|
+
const assign = (node) => {
|
|
699
|
+
const oldId = node.id;
|
|
700
|
+
node.id = freshId();
|
|
701
|
+
if (opts.styleId === 'regenerate') {
|
|
702
|
+
if (node.styleId)
|
|
703
|
+
node.styleId = freshId();
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
node.styleId = undefined;
|
|
707
|
+
}
|
|
708
|
+
if (oldId)
|
|
709
|
+
idMap.set(oldId, node.id);
|
|
710
|
+
(node.children || []).forEach(assign);
|
|
711
|
+
};
|
|
712
|
+
assign(root);
|
|
713
|
+
remapNodeReferences(root, idMap);
|
|
714
|
+
}
|
|
715
|
+
/** Remap absolute node-id references inside a subtree to their new ids (per `idMap`). Ids not in
|
|
716
|
+
* the map (references to nodes outside the cloned subtree) are preserved. */
|
|
717
|
+
function remapNodeReferences(node, idMap) {
|
|
718
|
+
const triggers = node.stateTriggers;
|
|
719
|
+
if (triggers) {
|
|
720
|
+
for (const state of Object.keys(triggers)) {
|
|
721
|
+
const mapped = idMap.get(triggers[state]);
|
|
722
|
+
if (mapped)
|
|
723
|
+
triggers[state] = mapped;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
for (const interaction of node.interactions || []) {
|
|
727
|
+
const actions = [...(interaction.actions || []), ...(interaction.reverseActions || [])];
|
|
728
|
+
for (const action of actions) {
|
|
729
|
+
if (action?.target && action.target !== 'self') {
|
|
730
|
+
const mapped = idMap.get(action.target);
|
|
731
|
+
if (mapped)
|
|
732
|
+
action.target = mapped;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
(node.children || []).forEach(child => remapNodeReferences(child, idMap));
|
|
737
|
+
}
|
|
738
|
+
|
|
680
739
|
/**
|
|
681
740
|
* Locate a node within a forest (array of root nodes + their descendants) by
|
|
682
741
|
* reference identity. Returns the parent array holding the node and its index,
|
|
@@ -1116,14 +1175,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
1116
1175
|
|
|
1117
1176
|
function deepCloneNode(node) {
|
|
1118
1177
|
const clone = JSON.parse(JSON.stringify(node));
|
|
1119
|
-
|
|
1178
|
+
// Fresh ids + remap intra-subtree references (stateTriggers, interaction targets) so a cloned
|
|
1179
|
+
// structure stays self-consistent — e.g. trigger-hover keeps pointing at the clone's own trigger.
|
|
1180
|
+
regenerateNodeIds(clone);
|
|
1120
1181
|
return clone;
|
|
1121
1182
|
}
|
|
1122
|
-
function regenerateIds(node) {
|
|
1123
|
-
node.id = Math.random().toString(36).substr(2, 9);
|
|
1124
|
-
node.styleId = undefined;
|
|
1125
|
-
(node.children || []).forEach(regenerateIds);
|
|
1126
|
-
}
|
|
1127
1183
|
class DragEngineService {
|
|
1128
1184
|
constructor(registry, symbolRegistry) {
|
|
1129
1185
|
this.registry = registry;
|
|
@@ -3365,6 +3421,27 @@ class RenderDirective {
|
|
|
3365
3421
|
}
|
|
3366
3422
|
return undefined;
|
|
3367
3423
|
}
|
|
3424
|
+
/** Nearest ANCESTOR of the styled element that is a registered iox-node AND contains the trigger
|
|
3425
|
+
* element — i.e. the DOM equivalent of `nearestCommonAncestorId`, resolved per rendered instance.
|
|
3426
|
+
* Used to re-emit a `trigger-hover` rule after a move/duplicate. Returns undefined if the trigger
|
|
3427
|
+
* isn't in the DOM yet (caller then skips rather than clobbering the existing rule). */
|
|
3428
|
+
resolveTargetedScopeId(styledEl, triggerCssId) {
|
|
3429
|
+
let el = styledEl?.parentElement ?? null;
|
|
3430
|
+
while (el) {
|
|
3431
|
+
let cssId;
|
|
3432
|
+
for (let i = 0; i < el.classList.length; i++) {
|
|
3433
|
+
const c = el.classList[i];
|
|
3434
|
+
if (c.startsWith('iox-node-')) {
|
|
3435
|
+
cssId = c.slice('iox-node-'.length);
|
|
3436
|
+
break;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
if (cssId && el.querySelector(`.iox-node-${triggerCssId}`))
|
|
3440
|
+
return cssId;
|
|
3441
|
+
el = el.parentElement;
|
|
3442
|
+
}
|
|
3443
|
+
return undefined;
|
|
3444
|
+
}
|
|
3368
3445
|
findParentNodeElement(target) {
|
|
3369
3446
|
let el = target;
|
|
3370
3447
|
while (el) {
|
|
@@ -3401,14 +3478,16 @@ class RenderDirective {
|
|
|
3401
3478
|
else {
|
|
3402
3479
|
componentRef = this.vcr.createComponent(componentClass, { injector: this.injector });
|
|
3403
3480
|
}
|
|
3404
|
-
// Apply regular trait defaults (title, image, description, etc.)
|
|
3405
|
-
//
|
|
3406
|
-
//
|
|
3407
|
-
//
|
|
3481
|
+
// Apply regular trait defaults (title, image, description, etc.). safeSetInput() uses
|
|
3482
|
+
// setInput() for declared inputs (marks the view dirty, integrates with CD + signal inputs)
|
|
3483
|
+
// and falls back to direct assignment for anything the component doesn't declare — so a
|
|
3484
|
+
// trait that has no matching @Input (e.g. `sourcePath` on a SliderContainer) never emits the
|
|
3485
|
+
// NG0303 console error that a bare setInput() would. Skip SectionLabel traits — they are
|
|
3486
|
+
// UI-only panel headers with no matching input.
|
|
3408
3487
|
Object.values(node.traits || {}).forEach((trait) => {
|
|
3409
3488
|
if (trait.type === 'sectionLabel')
|
|
3410
3489
|
return;
|
|
3411
|
-
componentRef
|
|
3490
|
+
safeSetInput(componentRef, trait.name, trait.default);
|
|
3412
3491
|
});
|
|
3413
3492
|
// Build initial style map from styleTraits defaults.
|
|
3414
3493
|
const initialStyle = {};
|
|
@@ -3446,6 +3525,21 @@ class RenderDirective {
|
|
|
3446
3525
|
continue;
|
|
3447
3526
|
this.styleRegistry.upsert(cssId, composeVirtualTraits(stateMap, initialStyle), state, relativeToId);
|
|
3448
3527
|
}
|
|
3528
|
+
else if (TARGETED_STATES.includes(state)) {
|
|
3529
|
+
// Targeted states (trigger-hover) compile to a `:has()` scoped to the nearest
|
|
3530
|
+
// common ancestor of the styled node + the chosen trigger. On a re-render (move,
|
|
3531
|
+
// duplicate, drop) we must RE-EMIT with a freshly-resolved scope — otherwise the
|
|
3532
|
+
// rule is clobbered and the hover stops working. Resolve the scope from the live
|
|
3533
|
+
// DOM (works per-instance); SKIP if the trigger isn't rendered yet, so we don't
|
|
3534
|
+
// clobber the correct rule page-ui's applyStateEnhancements already produced.
|
|
3535
|
+
const triggerCssId = node.stateTriggers?.[state];
|
|
3536
|
+
if (!triggerCssId)
|
|
3537
|
+
continue;
|
|
3538
|
+
const scopeId = this.resolveTargetedScopeId(childEl, triggerCssId);
|
|
3539
|
+
if (!scopeId)
|
|
3540
|
+
continue;
|
|
3541
|
+
this.styleRegistry.upsert(cssId, composeVirtualTraits(stateMap, initialStyle), state, scopeId, triggerCssId);
|
|
3542
|
+
}
|
|
3449
3543
|
else {
|
|
3450
3544
|
this.styleRegistry.upsert(cssId, composeVirtualTraits(stateMap, initialStyle), state);
|
|
3451
3545
|
}
|
|
@@ -3567,15 +3661,6 @@ class RenderDirective {
|
|
|
3567
3661
|
this.interactionEngine.attachTo(node, nativeEl);
|
|
3568
3662
|
}
|
|
3569
3663
|
}
|
|
3570
|
-
/** Try setInput(); fall back to direct assignment for non-@Input properties. */
|
|
3571
|
-
safeSetInput(ref, name, value) {
|
|
3572
|
-
try {
|
|
3573
|
-
ref.setInput(name, value);
|
|
3574
|
-
}
|
|
3575
|
-
catch {
|
|
3576
|
-
ref.instance[name] = value;
|
|
3577
|
-
}
|
|
3578
|
-
}
|
|
3579
3664
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: RenderDirective, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i0.EnvironmentInjector }, { token: DOCUMENT }, { token: ComponentRegistryService }, { token: OverlayService }, { token: StyleRegistryService }, { token: InteractionEngineService }, { token: i0.ChangeDetectorRef }, { token: PanelEventService }, { token: DragEngineService }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3580
3665
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.11", type: RenderDirective, isStandalone: false, selector: "[ioxRender]", inputs: { ioxRender: "ioxRender", ioxDragSourceId: "ioxDragSourceId" }, outputs: { onClick: "onClick", onMouseEnter: "onMouseEnter", onMouseLeave: "onMouseLeave" }, ngImport: i0 }); }
|
|
3581
3666
|
}
|
|
@@ -5294,15 +5379,11 @@ class BuilderComponent {
|
|
|
5294
5379
|
}
|
|
5295
5380
|
deepCloneWithNewIds(node) {
|
|
5296
5381
|
const clone = JSON.parse(JSON.stringify(node));
|
|
5297
|
-
|
|
5382
|
+
// Fresh ids + remap intra-subtree references (stateTriggers, interaction targets) so a
|
|
5383
|
+
// duplicated/pasted structure stays self-consistent (trigger-hover keeps its own trigger).
|
|
5384
|
+
regenerateNodeIds(clone, { styleId: 'regenerate' });
|
|
5298
5385
|
return clone;
|
|
5299
5386
|
}
|
|
5300
|
-
assignNewIds(node) {
|
|
5301
|
-
node.id = Math.random().toString(36).slice(2, 10);
|
|
5302
|
-
if (node.styleId)
|
|
5303
|
-
node.styleId = Math.random().toString(36).slice(2, 10);
|
|
5304
|
-
node.children?.forEach(child => this.assignNewIds(child));
|
|
5305
|
-
}
|
|
5306
5387
|
_stripGlobalFlags(node) {
|
|
5307
5388
|
node.isGlobal = false;
|
|
5308
5389
|
node.globalPosition = undefined;
|