@vectoriox/iox-builder 4.26.0 → 4.27.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.
|
@@ -21,6 +21,7 @@ export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTra
|
|
|
21
21
|
import Lenis from 'lenis';
|
|
22
22
|
import { Subject, BehaviorSubject, of, forkJoin } from 'rxjs';
|
|
23
23
|
import interact from 'interactjs';
|
|
24
|
+
import { BEHAVIOUR_ACTION_TYPES } from '@vectoriox/iox-ui/actions-core';
|
|
24
25
|
import Moveable from 'moveable';
|
|
25
26
|
import Selecto from 'selecto';
|
|
26
27
|
import { map, catchError } from 'rxjs/operators';
|
|
@@ -3268,6 +3269,15 @@ class InteractionEngineService {
|
|
|
3268
3269
|
this.executeDialogAction(action);
|
|
3269
3270
|
continue;
|
|
3270
3271
|
}
|
|
3272
|
+
// Tier-A behaviour (A1c). The canvas-is-live rules are catalog DATA
|
|
3273
|
+
// (ELEMENT_ACTION_DESCRIPTORS): copy runs, scrollTo runs (scrollIntoView — the frame
|
|
3274
|
+
// scrolls natively here; the Lenis rule is the LIVE side's), navigate and submitForm
|
|
3275
|
+
// SIMULATE — a dispatched event the host surfaces as a toast, never a route change
|
|
3276
|
+
// or a fake submit under the author's feet.
|
|
3277
|
+
if (BEHAVIOUR_ACTION_TYPES.has(action.type)) {
|
|
3278
|
+
this.executeBehaviourAction(node, action, selfEl);
|
|
3279
|
+
continue;
|
|
3280
|
+
}
|
|
3271
3281
|
// Context actions write STATE, not animation. `selfEl` is deliberate: $item is read by
|
|
3272
3282
|
// walking up from the element actually hovered/clicked, which for a repeater PREVIEW ROW
|
|
3273
3283
|
// is the clone — so each row publishes its own item, exactly as on the live site.
|
|
@@ -3317,6 +3327,28 @@ class InteractionEngineService {
|
|
|
3317
3327
|
// MERGE, not replace — a page can hold several repeaters, each publishing its own source.
|
|
3318
3328
|
this.contextData = { ...this.contextData, ...(data ?? {}) };
|
|
3319
3329
|
}
|
|
3330
|
+
executeBehaviourAction(node, action, selfEl) {
|
|
3331
|
+
switch (action.type) {
|
|
3332
|
+
case 'copyToClipboard': {
|
|
3333
|
+
const text = String(action.params?.['text'] ?? '');
|
|
3334
|
+
if (text)
|
|
3335
|
+
navigator.clipboard?.writeText(text).catch(() => { });
|
|
3336
|
+
return;
|
|
3337
|
+
}
|
|
3338
|
+
case 'scrollTo': {
|
|
3339
|
+
const target = this.resolveTarget(node, action, selfEl);
|
|
3340
|
+
target?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
3341
|
+
return;
|
|
3342
|
+
}
|
|
3343
|
+
case 'navigate':
|
|
3344
|
+
case 'submitForm': {
|
|
3345
|
+
// Simulated: the host (the admin app) listens and shows "would …" as a toast.
|
|
3346
|
+
const detail = { type: action.type, params: action.params ?? {}, target: action.target };
|
|
3347
|
+
window.dispatchEvent(new CustomEvent('iox-action-simulated', { detail }));
|
|
3348
|
+
return;
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3320
3352
|
executeDialogAction(action) {
|
|
3321
3353
|
const dialog = action.target && action.target !== 'self' ? this.instanceRegistry.get(action.target) : null;
|
|
3322
3354
|
if (!dialog)
|
|
@@ -6565,11 +6597,32 @@ class BuilderComponent {
|
|
|
6565
6597
|
this.lenis = undefined;
|
|
6566
6598
|
this.lenisRafId = undefined;
|
|
6567
6599
|
}
|
|
6600
|
+
/**
|
|
6601
|
+
* K5 (actions plan): actions need NAMED targets — the panel lists only labeled nodes, so an
|
|
6602
|
+
* unlabeled Dialog is unpickable. Every insert path labels the node "<Type>" or "<Type> N",
|
|
6603
|
+
* counting existing labels of that family across the whole tree.
|
|
6604
|
+
*/
|
|
6605
|
+
autoLabel(config) {
|
|
6606
|
+
if (!config?.type || config.label)
|
|
6607
|
+
return;
|
|
6608
|
+
const base = String(config.type).replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
6609
|
+
let count = 0;
|
|
6610
|
+
const walk = (nodes) => {
|
|
6611
|
+
for (const n of nodes ?? []) {
|
|
6612
|
+
if (typeof n?.label === 'string' && (n.label === base || n.label.startsWith(base + ' ')))
|
|
6613
|
+
count++;
|
|
6614
|
+
walk(n?.children);
|
|
6615
|
+
}
|
|
6616
|
+
};
|
|
6617
|
+
walk(this.layout);
|
|
6618
|
+
config.label = count === 0 ? base : `${base} ${count + 1}`;
|
|
6619
|
+
}
|
|
6568
6620
|
addComponent(name) {
|
|
6569
6621
|
const config = this.registry.createConfig(name);
|
|
6570
6622
|
if (!config) {
|
|
6571
6623
|
return;
|
|
6572
6624
|
}
|
|
6625
|
+
this.autoLabel(config);
|
|
6573
6626
|
this.layout.push(config);
|
|
6574
6627
|
}
|
|
6575
6628
|
onDrop(event) {
|
|
@@ -6579,6 +6632,7 @@ class BuilderComponent {
|
|
|
6579
6632
|
const config = this.registry.createConfig(payload.data);
|
|
6580
6633
|
if (!config)
|
|
6581
6634
|
return;
|
|
6635
|
+
this.autoLabel(config);
|
|
6582
6636
|
this.layout.splice(insertIndex, 0, config);
|
|
6583
6637
|
this.cdr.markForCheck();
|
|
6584
6638
|
this._selectAfterDrop(config);
|