@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);