@timeax/digital-service-engine 0.3.1 → 0.3.2

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.
@@ -7479,13 +7479,7 @@ function duplicate(ctx, ref, opts = {}) {
7479
7479
  try {
7480
7480
  let newId2 = "";
7481
7481
  ctx.transact("duplicate", () => {
7482
- if (ref.kind === "tag") {
7483
- newId2 = duplicateTag(ctx, ref.id, opts);
7484
- } else if (ref.kind === "field") {
7485
- newId2 = duplicateField(ctx, ref.id, opts);
7486
- } else {
7487
- newId2 = duplicateOption(ctx, ref.fieldId, ref.id, opts);
7488
- }
7482
+ newId2 = duplicateInPlace(ctx, ref, opts);
7489
7483
  });
7490
7484
  return newId2;
7491
7485
  } catch (err) {
@@ -7493,6 +7487,74 @@ function duplicate(ctx, ref, opts = {}) {
7493
7487
  throw err;
7494
7488
  }
7495
7489
  }
7490
+ function duplicateMany(ctx, ids, opts = {}) {
7491
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
7492
+ if (!ordered.length) return [];
7493
+ const snapBefore = ctx.makeSnapshot("duplicateMany:before");
7494
+ try {
7495
+ const created = [];
7496
+ ctx.transact("duplicateMany", () => {
7497
+ var _a, _b, _c;
7498
+ const props = ctx.getProps();
7499
+ const selectedFields = /* @__PURE__ */ new Set();
7500
+ for (const id of ordered) {
7501
+ if (ctx.isFieldId(id) && ((_a = props.fields) != null ? _a : []).some((f) => f.id === id)) {
7502
+ selectedFields.add(id);
7503
+ }
7504
+ }
7505
+ for (const id of ordered) {
7506
+ if (ctx.isTagId(id)) {
7507
+ if (!((_b = ctx.getProps().filters) != null ? _b : []).some((t) => t.id === id)) continue;
7508
+ created.push(
7509
+ duplicateInPlace(ctx, { kind: "tag", id }, opts)
7510
+ );
7511
+ continue;
7512
+ }
7513
+ if (ctx.isFieldId(id)) {
7514
+ if (!((_c = ctx.getProps().fields) != null ? _c : []).some((f) => f.id === id)) continue;
7515
+ created.push(
7516
+ duplicateInPlace(ctx, { kind: "field", id }, opts)
7517
+ );
7518
+ continue;
7519
+ }
7520
+ if (ctx.isOptionId(id)) {
7521
+ const owner = ownerFieldOfOption(ctx.getProps(), id);
7522
+ if (!owner) continue;
7523
+ if (selectedFields.has(owner.fieldId)) continue;
7524
+ created.push(
7525
+ duplicateInPlace(
7526
+ ctx,
7527
+ { kind: "option", fieldId: owner.fieldId, id },
7528
+ opts
7529
+ )
7530
+ );
7531
+ }
7532
+ }
7533
+ });
7534
+ return created;
7535
+ } catch (err) {
7536
+ ctx.loadSnapshot(snapBefore, "undo");
7537
+ throw err;
7538
+ }
7539
+ }
7540
+ function duplicateInPlace(ctx, ref, opts = {}) {
7541
+ if (ref.kind === "tag") {
7542
+ return duplicateTag(ctx, ref.id, opts);
7543
+ }
7544
+ if (ref.kind === "field") {
7545
+ return duplicateField(ctx, ref.id, opts);
7546
+ }
7547
+ return duplicateOption(ctx, ref.fieldId, ref.id, opts);
7548
+ }
7549
+ function ownerFieldOfOption(props, optionId) {
7550
+ var _a, _b;
7551
+ for (const field of (_a = props.fields) != null ? _a : []) {
7552
+ if (((_b = field.options) != null ? _b : []).some((o) => o.id === optionId)) {
7553
+ return { fieldId: field.id };
7554
+ }
7555
+ }
7556
+ return null;
7557
+ }
7496
7558
  function duplicateTag(ctx, tagId, opts) {
7497
7559
  var _a, _b, _c, _d;
7498
7560
  const props = ctx.getProps();
@@ -7779,6 +7841,129 @@ function ensureServiceExists(opts, id) {
7779
7841
  }
7780
7842
 
7781
7843
  // src/react/canvas/editor/editor-nodes.ts
7844
+ var RELATION_MAP_KEYS = [
7845
+ "includes_for_buttons",
7846
+ "excludes_for_buttons",
7847
+ "includes_for_options",
7848
+ "excludes_for_options"
7849
+ ];
7850
+ function stripDeletedIds(ids) {
7851
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
7852
+ return { ordered, set: new Set(ordered) };
7853
+ }
7854
+ function cleanTagRelationsForDeleted(p, deleted) {
7855
+ var _a;
7856
+ for (const t of (_a = p.filters) != null ? _a : []) {
7857
+ if (t.bind_id && deleted.has(String(t.bind_id))) delete t.bind_id;
7858
+ if (t.includes) {
7859
+ const next = t.includes.filter((x) => !deleted.has(String(x)));
7860
+ if (next.length) t.includes = next;
7861
+ else delete t.includes;
7862
+ }
7863
+ if (t.excludes) {
7864
+ const next = t.excludes.filter((x) => !deleted.has(String(x)));
7865
+ if (next.length) t.excludes = next;
7866
+ else delete t.excludes;
7867
+ }
7868
+ }
7869
+ }
7870
+ function cleanFieldBindsForDeleted(p, deleted) {
7871
+ var _a;
7872
+ for (const f of (_a = p.fields) != null ? _a : []) {
7873
+ const bind = f.bind_id;
7874
+ if (!bind) continue;
7875
+ if (Array.isArray(bind)) {
7876
+ const next = bind.filter((x) => !deleted.has(String(x)));
7877
+ if (next.length) f.bind_id = next;
7878
+ else delete f.bind_id;
7879
+ continue;
7880
+ }
7881
+ if (deleted.has(String(bind))) delete f.bind_id;
7882
+ }
7883
+ }
7884
+ function cleanRelationMapsForDeleted(p, deleted) {
7885
+ var _a;
7886
+ for (const key of RELATION_MAP_KEYS) {
7887
+ const map = p[key];
7888
+ if (!map) continue;
7889
+ for (const mapKey of Object.keys(map)) {
7890
+ if (deleted.has(String(mapKey))) {
7891
+ delete map[mapKey];
7892
+ continue;
7893
+ }
7894
+ const next = ((_a = map[mapKey]) != null ? _a : []).filter(
7895
+ (item) => !deleted.has(String(item))
7896
+ );
7897
+ if (next.length) map[mapKey] = next;
7898
+ else delete map[mapKey];
7899
+ }
7900
+ if (!Object.keys(map).length) delete p[key];
7901
+ }
7902
+ }
7903
+ function cleanOrderForTagsForDeleted(p, deleted) {
7904
+ var _a, _b;
7905
+ const map = p.order_for_tags;
7906
+ if (!map) return;
7907
+ const fieldIds = new Set(((_a = p.fields) != null ? _a : []).map((f) => String(f.id)));
7908
+ for (const key of Object.keys(map)) {
7909
+ if (deleted.has(String(key))) {
7910
+ delete map[key];
7911
+ continue;
7912
+ }
7913
+ const next = ((_b = map[key]) != null ? _b : []).filter(
7914
+ (fid) => !deleted.has(String(fid)) && fieldIds.has(String(fid))
7915
+ );
7916
+ if (next.length) map[key] = next;
7917
+ else delete map[key];
7918
+ }
7919
+ if (!Object.keys(map).length) delete p.order_for_tags;
7920
+ }
7921
+ function cleanNoticesForDeleted(p, deleted) {
7922
+ var _a;
7923
+ if (!((_a = p.notices) == null ? void 0 : _a.length)) return;
7924
+ p.notices = p.notices.filter((n) => {
7925
+ const target = n.target;
7926
+ if (!target || target.scope === "global") return true;
7927
+ if (target.scope === "node" && deleted.has(String(target.node_id))) {
7928
+ return false;
7929
+ }
7930
+ return true;
7931
+ });
7932
+ if (!p.notices.length) delete p.notices;
7933
+ }
7934
+ function applyDeleteCleanup(p, deleted) {
7935
+ cleanTagRelationsForDeleted(p, deleted);
7936
+ cleanFieldBindsForDeleted(p, deleted);
7937
+ cleanRelationMapsForDeleted(p, deleted);
7938
+ cleanOrderForTagsForDeleted(p, deleted);
7939
+ cleanNoticesForDeleted(p, deleted);
7940
+ }
7941
+ function removeOptionInPlace(p, optionId) {
7942
+ var _a;
7943
+ const owner = ownerOfOption(p, optionId);
7944
+ if (!owner) return false;
7945
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === owner.fieldId);
7946
+ if (!(f == null ? void 0 : f.options)) return false;
7947
+ const before = f.options.length;
7948
+ f.options = f.options.filter((o) => o.id !== optionId);
7949
+ return f.options.length !== before;
7950
+ }
7951
+ function removeFieldInPlace(p, fieldId) {
7952
+ var _a, _b, _c, _d, _e;
7953
+ const field = ((_a = p.fields) != null ? _a : []).find((f) => f.id === fieldId);
7954
+ if (!field) return [];
7955
+ const deleted = [fieldId, ...((_b = field.options) != null ? _b : []).map((o) => String(o.id))];
7956
+ const before = ((_c = p.fields) != null ? _c : []).length;
7957
+ p.fields = ((_d = p.fields) != null ? _d : []).filter((f) => f.id !== fieldId);
7958
+ clearFieldButtonReceiverMaps(p, fieldId);
7959
+ return ((_e = p.fields) != null ? _e : []).length !== before ? deleted : [];
7960
+ }
7961
+ function removeTagInPlace(p, tagId) {
7962
+ var _a, _b, _c;
7963
+ const before = ((_a = p.filters) != null ? _a : []).length;
7964
+ p.filters = ((_b = p.filters) != null ? _b : []).filter((t) => t.id !== tagId);
7965
+ return ((_c = p.filters) != null ? _c : []).length !== before;
7966
+ }
7782
7967
  function reLabel(ctx, id, nextLabel) {
7783
7968
  const label = String(nextLabel != null ? nextLabel : "").trim();
7784
7969
  ctx.exec({
@@ -7913,22 +8098,9 @@ function removeOption(ctx, optionId) {
7913
8098
  ctx.exec({
7914
8099
  name: "removeOption",
7915
8100
  do: () => ctx.patchProps((p) => {
7916
- var _a;
7917
- const owner = ownerOfOption(p, optionId);
7918
- if (!owner) return;
7919
- const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === owner.fieldId);
7920
- if (!(f == null ? void 0 : f.options)) return;
7921
- f.options = f.options.filter((o) => o.id !== optionId);
7922
- const maps = [
7923
- "includes_for_options",
7924
- "excludes_for_options"
7925
- ];
7926
- for (const m of maps) {
7927
- const map = p[m];
7928
- if (!map) continue;
7929
- if (map[optionId]) delete map[optionId];
7930
- if (!Object.keys(map).length) delete p[m];
7931
- }
8101
+ const removed = removeOptionInPlace(p, optionId);
8102
+ if (!removed) return;
8103
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([optionId]));
7932
8104
  }),
7933
8105
  undo: () => ctx.undo()
7934
8106
  });
@@ -8117,21 +8289,10 @@ function removeTag(ctx, id) {
8117
8289
  ctx.exec({
8118
8290
  name: "removeTag",
8119
8291
  do: () => ctx.patchProps((p) => {
8120
- var _a, _b, _c, _d, _e;
8121
8292
  prevSlice = cloneDeep3(p);
8122
- p.filters = ((_a = p.filters) != null ? _a : []).filter((t) => t.id !== id);
8123
- for (const t of (_b = p.filters) != null ? _b : []) {
8124
- if (t.bind_id === id) delete t.bind_id;
8125
- t.includes = ((_c = t.includes) != null ? _c : []).filter((x) => x !== id);
8126
- t.excludes = ((_d = t.excludes) != null ? _d : []).filter((x) => x !== id);
8127
- }
8128
- for (const f of (_e = p.fields) != null ? _e : []) {
8129
- if (Array.isArray(f.bind_id)) {
8130
- f.bind_id = f.bind_id.filter((x) => x !== id);
8131
- } else if (f.bind_id === id) {
8132
- delete f.bind_id;
8133
- }
8134
- }
8293
+ const removed = removeTagInPlace(p, id);
8294
+ if (!removed) return;
8295
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([id]));
8135
8296
  }),
8136
8297
  undo: () => ctx.replaceProps(prevSlice)
8137
8298
  });
@@ -8199,58 +8360,23 @@ function removeField(ctx, id) {
8199
8360
  ctx.exec({
8200
8361
  name: "removeField",
8201
8362
  do: () => ctx.patchProps((p) => {
8202
- var _a, _b, _c, _d, _e, _f;
8203
8363
  prevSlice = cloneDeep3(p);
8204
- p.fields = ((_a = p.fields) != null ? _a : []).filter((f) => f.id !== id);
8205
- clearFieldButtonReceiverMaps(p, id);
8206
- for (const mapKey of [
8207
- "includes_for_buttons",
8208
- "excludes_for_buttons"
8209
- ]) {
8210
- const m = p[mapKey];
8211
- if (!m) continue;
8212
- for (const k of Object.keys(m)) {
8213
- m[k] = ((_b = m[k]) != null ? _b : []).filter((fid) => fid !== id);
8214
- if (!((_c = m[k]) == null ? void 0 : _c.length)) delete m[k];
8215
- }
8216
- }
8217
- for (const t of (_d = p.filters) != null ? _d : []) {
8218
- t.includes = ((_e = t.includes) != null ? _e : []).filter((x) => x !== id);
8219
- t.excludes = ((_f = t.excludes) != null ? _f : []).filter((x) => x !== id);
8220
- }
8364
+ const removedIds = removeFieldInPlace(p, id);
8365
+ if (!removedIds.length) return;
8366
+ applyDeleteCleanup(p, new Set(removedIds));
8221
8367
  }),
8222
8368
  undo: () => ctx.replaceProps(prevSlice)
8223
8369
  });
8224
8370
  }
8225
8371
  function remove(ctx, id) {
8372
+ const key = String(id);
8226
8373
  if (ctx.isTagId(id)) {
8227
8374
  ctx.exec({
8228
8375
  name: "removeTag",
8229
8376
  do: () => ctx.patchProps((p) => {
8230
- var _a, _b, _c, _d, _e, _f, _g, _h;
8231
- p.filters = ((_a = p.filters) != null ? _a : []).filter((t) => t.id !== id);
8232
- for (const t of (_b = p.filters) != null ? _b : []) {
8233
- if (t.bind_id === id) delete t.bind_id;
8234
- t.includes = ((_c = t.includes) != null ? _c : []).filter((x) => x !== id);
8235
- t.excludes = ((_d = t.excludes) != null ? _d : []).filter((x) => x !== id);
8236
- }
8237
- for (const f of (_e = p.fields) != null ? _e : []) {
8238
- if (Array.isArray(f.bind_id)) {
8239
- f.bind_id = f.bind_id.filter((x) => x !== id);
8240
- } else if (f.bind_id === id) {
8241
- delete f.bind_id;
8242
- }
8243
- }
8244
- if ((_f = p.order_for_tags) == null ? void 0 : _f[id]) delete p.order_for_tags[id];
8245
- for (const k of Object.keys((_g = p.order_for_tags) != null ? _g : {})) {
8246
- p.order_for_tags[k] = ((_h = p.order_for_tags[k]) != null ? _h : []).filter(
8247
- (fid) => {
8248
- var _a2;
8249
- return ((_a2 = p.fields) != null ? _a2 : []).some((f) => f.id === fid);
8250
- }
8251
- );
8252
- if (!p.order_for_tags[k].length) delete p.order_for_tags[k];
8253
- }
8377
+ const removed = removeTagInPlace(p, key);
8378
+ if (!removed) return;
8379
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([key]));
8254
8380
  }),
8255
8381
  undo: () => ctx.undo()
8256
8382
  });
@@ -8260,42 +8386,67 @@ function remove(ctx, id) {
8260
8386
  ctx.exec({
8261
8387
  name: "removeField",
8262
8388
  do: () => ctx.patchProps((p) => {
8263
- var _a, _b, _c, _d, _e, _f, _g, _h;
8264
- p.fields = ((_a = p.fields) != null ? _a : []).filter((f) => f.id !== id);
8265
- for (const t of (_b = p.filters) != null ? _b : []) {
8266
- t.includes = ((_c = t.includes) != null ? _c : []).filter((x) => x !== id);
8267
- t.excludes = ((_d = t.excludes) != null ? _d : []).filter((x) => x !== id);
8268
- }
8269
- for (const k of Object.keys((_e = p.order_for_tags) != null ? _e : {})) {
8270
- p.order_for_tags[k] = ((_f = p.order_for_tags[k]) != null ? _f : []).filter(
8271
- (fid) => fid !== id
8272
- );
8273
- if (!p.order_for_tags[k].length) delete p.order_for_tags[k];
8274
- }
8275
- const maps = [
8276
- "includes_for_options",
8277
- "excludes_for_options"
8278
- ];
8279
- for (const m of maps) {
8280
- const map = p[m];
8281
- if (!map) continue;
8282
- for (const key of Object.keys(map)) {
8283
- map[key] = ((_g = map[key]) != null ? _g : []).filter((fid) => fid !== id);
8284
- if (!((_h = map[key]) == null ? void 0 : _h.length)) delete map[key];
8285
- }
8286
- if (!Object.keys(map).length) delete p[m];
8287
- }
8389
+ const removedIds = removeFieldInPlace(p, key);
8390
+ if (!removedIds.length) return;
8391
+ applyDeleteCleanup(p, new Set(removedIds));
8288
8392
  }),
8289
8393
  undo: () => ctx.undo()
8290
8394
  });
8291
8395
  return;
8292
8396
  }
8293
8397
  if (ctx.isOptionId(id)) {
8294
- removeOption(ctx, id);
8398
+ ctx.exec({
8399
+ name: "removeOption",
8400
+ do: () => ctx.patchProps((p) => {
8401
+ const removed = removeOptionInPlace(p, key);
8402
+ if (!removed) return;
8403
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([key]));
8404
+ }),
8405
+ undo: () => ctx.undo()
8406
+ });
8295
8407
  return;
8296
8408
  }
8297
8409
  throw new Error("remove: unknown id prefix");
8298
8410
  }
8411
+ function removeMany(ctx, ids) {
8412
+ const { ordered } = stripDeletedIds(ids);
8413
+ if (!ordered.length) return;
8414
+ ctx.transact("removeMany", () => {
8415
+ ctx.patchProps((p) => {
8416
+ var _a, _b, _c;
8417
+ const existingFieldIds = new Set(((_a = p.fields) != null ? _a : []).map((f) => String(f.id)));
8418
+ const existingTagIds = new Set(((_b = p.filters) != null ? _b : []).map((t) => String(t.id)));
8419
+ const existingOptionIds = new Set(
8420
+ ((_c = p.fields) != null ? _c : []).flatMap((f) => {
8421
+ var _a2;
8422
+ return ((_a2 = f.options) != null ? _a2 : []).map((o) => String(o.id));
8423
+ })
8424
+ );
8425
+ const fieldIds = ordered.filter((id) => ctx.isFieldId(id) && existingFieldIds.has(id));
8426
+ const fieldIdSet = new Set(fieldIds);
8427
+ const tagIds = ordered.filter((id) => ctx.isTagId(id) && existingTagIds.has(id));
8428
+ const optionIds = ordered.filter((id) => {
8429
+ if (!ctx.isOptionId(id) || !existingOptionIds.has(id)) return false;
8430
+ const owner = ownerOfOption(p, id);
8431
+ if (!owner) return false;
8432
+ return !fieldIdSet.has(String(owner.fieldId));
8433
+ });
8434
+ const deleted = /* @__PURE__ */ new Set();
8435
+ for (const optionId of optionIds) {
8436
+ if (removeOptionInPlace(p, optionId)) deleted.add(optionId);
8437
+ }
8438
+ for (const fieldId of fieldIds) {
8439
+ const removedIds = removeFieldInPlace(p, fieldId);
8440
+ for (const rid of removedIds) deleted.add(rid);
8441
+ }
8442
+ for (const tagId of tagIds) {
8443
+ if (removeTagInPlace(p, tagId)) deleted.add(tagId);
8444
+ }
8445
+ if (!deleted.size) return;
8446
+ applyDeleteCleanup(p, deleted);
8447
+ });
8448
+ });
8449
+ }
8299
8450
  function getNode(ctx, id) {
8300
8451
  var _a, _b, _c, _d;
8301
8452
  const props = ctx.getProps();
@@ -9540,6 +9691,9 @@ var Editor = class {
9540
9691
  duplicate(ref, opts = {}) {
9541
9692
  return duplicate(this.moduleCtx(), ref, opts);
9542
9693
  }
9694
+ duplicateMany(ids, opts = {}) {
9695
+ return duplicateMany(this.moduleCtx(), ids, opts);
9696
+ }
9543
9697
  reLabel(id, nextLabel) {
9544
9698
  return reLabel(this.moduleCtx(), id, nextLabel);
9545
9699
  }
@@ -9603,6 +9757,260 @@ var Editor = class {
9603
9757
  remove(id) {
9604
9758
  return remove(this.moduleCtx(), id);
9605
9759
  }
9760
+ removeMany(ids) {
9761
+ return removeMany(this.moduleCtx(), ids);
9762
+ }
9763
+ clearServiceMany(ids) {
9764
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9765
+ if (!ordered.length) return;
9766
+ this.transact("clearServiceMany", () => {
9767
+ this.patchProps((p) => {
9768
+ var _a, _b, _c, _d;
9769
+ for (const id of ordered) {
9770
+ if (this.isTagId(id)) {
9771
+ const t = ((_a = p.filters) != null ? _a : []).find((x) => x.id === id);
9772
+ if (t && "service_id" in t) delete t.service_id;
9773
+ continue;
9774
+ }
9775
+ if (this.isFieldId(id)) {
9776
+ const f = ((_b = p.fields) != null ? _b : []).find((x) => x.id === id);
9777
+ if (f && "service_id" in f) delete f.service_id;
9778
+ continue;
9779
+ }
9780
+ if (this.isOptionId(id)) {
9781
+ const own = ownerOfOption(p, id);
9782
+ if (!own) continue;
9783
+ const f = ((_c = p.fields) != null ? _c : []).find((x) => x.id === own.fieldId);
9784
+ const o = (_d = f == null ? void 0 : f.options) == null ? void 0 : _d.find((x) => x.id === id);
9785
+ if (o && "service_id" in o) delete o.service_id;
9786
+ }
9787
+ }
9788
+ });
9789
+ });
9790
+ }
9791
+ rebindMany(ids, targetTagId, opts) {
9792
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9793
+ if (!ordered.length) return;
9794
+ this.transact("rebindMany", () => {
9795
+ this.patchProps((p) => {
9796
+ var _a, _b, _c;
9797
+ const targetExists = ((_a = p.filters) != null ? _a : []).some((t) => t.id === targetTagId);
9798
+ if (!targetExists) return;
9799
+ for (const id of ordered) {
9800
+ if (this.isFieldId(id)) {
9801
+ const f = ((_b = p.fields) != null ? _b : []).find((x) => x.id === id);
9802
+ if (!f) continue;
9803
+ f.bind_id = targetTagId;
9804
+ continue;
9805
+ }
9806
+ if (this.isTagId(id)) {
9807
+ const t = ((_c = p.filters) != null ? _c : []).find((x) => x.id === id);
9808
+ if (!t) continue;
9809
+ if (!(opts == null ? void 0 : opts.allowTagCycles) && wouldCreateTagCycle(this.moduleCtx(), p, targetTagId, id)) {
9810
+ continue;
9811
+ }
9812
+ t.bind_id = targetTagId;
9813
+ }
9814
+ }
9815
+ });
9816
+ });
9817
+ }
9818
+ includeMany(receiverId, ids) {
9819
+ const accepted = Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))).filter((id) => id !== receiverId).filter((id) => this.getNode(id).data != null);
9820
+ if (!accepted.length) return;
9821
+ include(this.moduleCtx(), receiverId, accepted);
9822
+ }
9823
+ excludeMany(receiverId, ids) {
9824
+ const accepted = Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))).filter((id) => id !== receiverId).filter((id) => this.getNode(id).data != null);
9825
+ if (!accepted.length) return;
9826
+ exclude(this.moduleCtx(), receiverId, accepted);
9827
+ }
9828
+ clearRelationsMany(ids, mode = "both") {
9829
+ const selected = new Set(Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))));
9830
+ if (!selected.size) return;
9831
+ this.transact("clearRelationsMany", () => {
9832
+ this.patchProps((p) => {
9833
+ var _a, _b, _c;
9834
+ const clearOwned = mode === "owned" || mode === "both";
9835
+ const clearIncoming = mode === "incoming" || mode === "both";
9836
+ for (const t of (_a = p.filters) != null ? _a : []) {
9837
+ if (clearOwned && selected.has(t.id)) {
9838
+ delete t.includes;
9839
+ delete t.excludes;
9840
+ }
9841
+ if (clearIncoming) {
9842
+ if (t.includes) {
9843
+ t.includes = t.includes.filter((x) => !selected.has(String(x)));
9844
+ if (!t.includes.length) delete t.includes;
9845
+ }
9846
+ if (t.excludes) {
9847
+ t.excludes = t.excludes.filter((x) => !selected.has(String(x)));
9848
+ if (!t.excludes.length) delete t.excludes;
9849
+ }
9850
+ }
9851
+ }
9852
+ const maps = [
9853
+ "includes_for_buttons",
9854
+ "excludes_for_buttons",
9855
+ "includes_for_options",
9856
+ "excludes_for_options"
9857
+ ];
9858
+ for (const k of maps) {
9859
+ const map = p[k];
9860
+ if (!map) continue;
9861
+ for (const key of Object.keys(map)) {
9862
+ if (clearOwned && selected.has(String(key))) {
9863
+ delete map[key];
9864
+ continue;
9865
+ }
9866
+ if (clearIncoming) {
9867
+ map[key] = ((_b = map[key]) != null ? _b : []).filter((x) => !selected.has(String(x)));
9868
+ if (!((_c = map[key]) == null ? void 0 : _c.length)) delete map[key];
9869
+ }
9870
+ }
9871
+ if (!Object.keys(map).length) delete p[k];
9872
+ }
9873
+ });
9874
+ });
9875
+ }
9876
+ renameLabelsMany(ids, input) {
9877
+ var _a, _b;
9878
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9879
+ if (!ordered.length) return;
9880
+ const prefix = (_a = input.prefix) != null ? _a : "";
9881
+ const suffix = (_b = input.suffix) != null ? _b : "";
9882
+ this.transact("renameLabelsMany", () => {
9883
+ this.patchProps((p) => {
9884
+ var _a2, _b2, _c, _d, _e, _f, _g;
9885
+ for (const id of ordered) {
9886
+ if (this.isTagId(id)) {
9887
+ const t = ((_a2 = p.filters) != null ? _a2 : []).find((x) => x.id === id);
9888
+ if (t) t.label = `${prefix}${(_b2 = t.label) != null ? _b2 : ""}${suffix}`.trim();
9889
+ continue;
9890
+ }
9891
+ if (this.isFieldId(id)) {
9892
+ const f = ((_c = p.fields) != null ? _c : []).find((x) => x.id === id);
9893
+ if (f) f.label = `${prefix}${(_d = f.label) != null ? _d : ""}${suffix}`.trim();
9894
+ continue;
9895
+ }
9896
+ if (this.isOptionId(id)) {
9897
+ const own = ownerOfOption(p, id);
9898
+ if (!own) continue;
9899
+ const f = ((_e = p.fields) != null ? _e : []).find((x) => x.id === own.fieldId);
9900
+ const o = (_f = f == null ? void 0 : f.options) == null ? void 0 : _f.find((x) => x.id === id);
9901
+ if (o) o.label = `${prefix}${(_g = o.label) != null ? _g : ""}${suffix}`.trim();
9902
+ }
9903
+ }
9904
+ });
9905
+ });
9906
+ }
9907
+ setPricingRoleMany(ids, role) {
9908
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9909
+ if (!ordered.length) return;
9910
+ this.transact("setPricingRoleMany", () => {
9911
+ for (const id of ordered) {
9912
+ if (this.isFieldId(id) || this.isOptionId(id)) {
9913
+ this.setService(id, { pricing_role: role });
9914
+ }
9915
+ }
9916
+ });
9917
+ }
9918
+ clearFieldDefaultsMany(ids) {
9919
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9920
+ if (!ordered.length) return;
9921
+ this.transact("clearFieldDefaultsMany", () => {
9922
+ this.patchProps((p) => {
9923
+ var _a;
9924
+ for (const id of ordered) {
9925
+ if (!this.isFieldId(id)) continue;
9926
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === id);
9927
+ if (f && "defaults" in f) delete f.defaults;
9928
+ }
9929
+ });
9930
+ });
9931
+ }
9932
+ clearFieldValidationMany(ids) {
9933
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9934
+ if (!ordered.length) return;
9935
+ this.transact("clearFieldValidationMany", () => {
9936
+ this.patchProps((p) => {
9937
+ var _a;
9938
+ for (const id of ordered) {
9939
+ if (!this.isFieldId(id)) continue;
9940
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === id);
9941
+ if (f && "validation" in f) delete f.validation;
9942
+ }
9943
+ });
9944
+ });
9945
+ }
9946
+ autoCreateOptionsMany(ids, makeOption) {
9947
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9948
+ if (!ordered.length) return;
9949
+ this.transact("autoCreateOptionsMany", () => {
9950
+ this.patchProps((p) => {
9951
+ var _a, _b, _c, _d;
9952
+ for (const id of ordered) {
9953
+ if (!this.isFieldId(id)) continue;
9954
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === id);
9955
+ if (!f) continue;
9956
+ const opts = (_b = f.options) != null ? _b : f.options = [];
9957
+ if (opts.length > 0) continue;
9958
+ const next = (_c = makeOption == null ? void 0 : makeOption(id)) != null ? _c : { label: "Option label", value: "option" };
9959
+ opts.push({
9960
+ id: (_d = next.id) != null ? _d : this.moduleCtx().genId("o"),
9961
+ label: next.label,
9962
+ value: next.value
9963
+ });
9964
+ }
9965
+ });
9966
+ });
9967
+ }
9968
+ clearAllOptionsMany(ids) {
9969
+ var _a, _b;
9970
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9971
+ if (!ordered.length) return;
9972
+ const optionIds = [];
9973
+ const props = this.getProps();
9974
+ for (const id of ordered) {
9975
+ if (!this.isFieldId(id)) continue;
9976
+ const f = ((_a = props.fields) != null ? _a : []).find((x) => x.id === id);
9977
+ for (const o of (_b = f == null ? void 0 : f.options) != null ? _b : []) optionIds.push(o.id);
9978
+ }
9979
+ if (!optionIds.length) return;
9980
+ removeMany(this.moduleCtx(), optionIds);
9981
+ }
9982
+ removeNoticesForNodes(ids) {
9983
+ const selected = new Set(Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))));
9984
+ if (!selected.size) return;
9985
+ this.transact("removeNoticesForNodes", () => {
9986
+ this.patchProps((p) => {
9987
+ var _a;
9988
+ if (!((_a = p.notices) == null ? void 0 : _a.length)) return;
9989
+ p.notices = p.notices.filter((n) => {
9990
+ const target = n.target;
9991
+ if (!target || target.scope === "global") return true;
9992
+ if (target.scope === "node") return !selected.has(String(target.node_id));
9993
+ return true;
9994
+ });
9995
+ if (!p.notices.length) delete p.notices;
9996
+ });
9997
+ });
9998
+ }
9999
+ setNoticesVisibilityForNodes(ids, type) {
10000
+ const selected = new Set(Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))));
10001
+ if (!selected.size) return;
10002
+ this.transact("setNoticesVisibilityForNodes", () => {
10003
+ this.patchProps((p) => {
10004
+ var _a;
10005
+ for (const n of (_a = p.notices) != null ? _a : []) {
10006
+ const target = n.target;
10007
+ if ((target == null ? void 0 : target.scope) === "node" && selected.has(String(target.node_id))) {
10008
+ n.type = type;
10009
+ }
10010
+ }
10011
+ });
10012
+ });
10013
+ }
9606
10014
  getNode(id) {
9607
10015
  return getNode(this.moduleCtx(), id);
9608
10016
  }
@@ -9846,9 +10254,8 @@ var Editor = class {
9846
10254
  Array.isArray(canvas.selection) ? canvas.selection : Array.from(canvas.selection)
9847
10255
  );
9848
10256
  }
9849
- } else {
9850
- this.api.refreshGraph();
9851
10257
  }
10258
+ this.api.refreshGraph();
9852
10259
  this.emit("editor:change", { props: s.props, reason, snapshot: s });
9853
10260
  }
9854
10261
  pushHistory(snap) {
@@ -10936,12 +11343,12 @@ function useCanvasOwned(initialProps, canvasOpts, builderOpts) {
10936
11343
  // src/react/workspace/context/hooks/use-canvas.ts
10937
11344
  import * as React16 from "react";
10938
11345
  import { useMemo as useMemo15 } from "react";
10939
- function deriveSelectionInfo(props, ids) {
11346
+ function deriveSelectionInfo(nodeMap, ids) {
10940
11347
  const tags = [];
10941
11348
  const fields = [];
10942
11349
  const options = [];
10943
11350
  for (const id of ids) {
10944
- const node = props.get(id);
11351
+ const node = nodeMap.get(id);
10945
11352
  if (!node) continue;
10946
11353
  if (node.kind == "tag") {
10947
11354
  tags.push(id);
@@ -10968,6 +11375,49 @@ function deriveSelectionInfo(props, ids) {
10968
11375
  optionIds: uniq2(options)
10969
11376
  };
10970
11377
  }
11378
+ function noticeTargetsSelection(notice, selected) {
11379
+ const target = notice.target;
11380
+ if (target.scope === "global") return false;
11381
+ return selected.has(String(target.node_id));
11382
+ }
11383
+ function deriveSelectionCapabilities(props, selectionInfo) {
11384
+ var _a, _b, _c;
11385
+ const selected = new Set(selectionInfo.ids.map(String));
11386
+ const fields = (_a = props == null ? void 0 : props.fields) != null ? _a : [];
11387
+ const tags = (_b = props == null ? void 0 : props.filters) != null ? _b : [];
11388
+ const notices = (_c = props == null ? void 0 : props.notices) != null ? _c : [];
11389
+ const hasSelectedFieldWithOptions = fields.some(
11390
+ (f) => {
11391
+ var _a2, _b2;
11392
+ return selected.has(String(f.id)) && ((_b2 = (_a2 = f.options) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0;
11393
+ }
11394
+ );
11395
+ const hasServiceBearingNodes = tags.some(
11396
+ (t) => selected.has(String(t.id)) && t.service_id !== void 0 && t.service_id !== null
11397
+ ) || fields.some(
11398
+ (f) => selected.has(String(f.id)) && f.service_id !== void 0 && f.service_id !== null
11399
+ ) || fields.some(
11400
+ (f) => {
11401
+ var _a2;
11402
+ return ((_a2 = f.options) != null ? _a2 : []).some(
11403
+ (o) => selected.has(String(o.id)) && o.service_id !== void 0 && o.service_id !== null
11404
+ );
11405
+ }
11406
+ );
11407
+ const hasNoticesForSelection = notices.some(
11408
+ (n) => noticeTargetsSelection(n, selected)
11409
+ );
11410
+ return {
11411
+ hasTags: selectionInfo.tagIds.length > 0,
11412
+ hasFields: selectionInfo.fieldIds.length > 0,
11413
+ hasOptions: selectionInfo.optionIds.length > 0,
11414
+ hasServiceBearingNodes,
11415
+ hasSelectedFieldWithOptions,
11416
+ hasNoticesForSelection,
11417
+ canIncludeExcludeTargets: selectionInfo.tagIds.length + selectionInfo.fieldIds.length + selectionInfo.optionIds.length > 0,
11418
+ canRebind: selectionInfo.fieldIds.length > 0 || selectionInfo.tagIds.length > 0
11419
+ };
11420
+ }
10971
11421
  function tagBindIds(tag) {
10972
11422
  const bind = tag.bind_id;
10973
11423
  if (!bind) return [];
@@ -11107,7 +11557,11 @@ function useCanvas() {
11107
11557
  });
11108
11558
  return off;
11109
11559
  }, [api]);
11110
- const selector = useMemo15(() => createNodeIndex(api.builder), [props]);
11560
+ const selector = useMemo15(() => createNodeIndex(api.builder), [api.builder, props]);
11561
+ const selectionCapabilities = React16.useMemo(
11562
+ () => deriveSelectionCapabilities(props, selectionInfo),
11563
+ [props, selectionInfo]
11564
+ );
11111
11565
  return React16.useMemo(
11112
11566
  () => ({
11113
11567
  api,
@@ -11116,6 +11570,7 @@ function useCanvas() {
11116
11570
  props,
11117
11571
  selection,
11118
11572
  selectionInfo,
11573
+ selectionCapabilities,
11119
11574
  selector,
11120
11575
  activeId,
11121
11576
  setActive
@@ -11127,6 +11582,7 @@ function useCanvas() {
11127
11582
  props,
11128
11583
  selection,
11129
11584
  selectionInfo,
11585
+ selectionCapabilities,
11130
11586
  selector,
11131
11587
  activeId,
11132
11588
  setActive
@@ -13813,6 +14269,7 @@ export {
13813
14269
  WorkspaceProvider,
13814
14270
  createMemoryWorkspaceBackend,
13815
14271
  createPollAdapter,
14272
+ deriveSelectionCapabilities,
13816
14273
  useCanvas,
13817
14274
  useCanvasAPI,
13818
14275
  useCanvasFromBuilder,