@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.
@@ -37,6 +37,7 @@ __export(workspace_exports, {
37
37
  WorkspaceProvider: () => WorkspaceProvider,
38
38
  createMemoryWorkspaceBackend: () => createMemoryWorkspaceBackend,
39
39
  createPollAdapter: () => createPollAdapter,
40
+ deriveSelectionCapabilities: () => deriveSelectionCapabilities,
40
41
  useCanvas: () => useCanvas,
41
42
  useCanvasAPI: () => useCanvasAPI,
42
43
  useCanvasFromBuilder: () => useCanvasFromBuilder,
@@ -7522,13 +7523,7 @@ function duplicate(ctx, ref, opts = {}) {
7522
7523
  try {
7523
7524
  let newId2 = "";
7524
7525
  ctx.transact("duplicate", () => {
7525
- if (ref.kind === "tag") {
7526
- newId2 = duplicateTag(ctx, ref.id, opts);
7527
- } else if (ref.kind === "field") {
7528
- newId2 = duplicateField(ctx, ref.id, opts);
7529
- } else {
7530
- newId2 = duplicateOption(ctx, ref.fieldId, ref.id, opts);
7531
- }
7526
+ newId2 = duplicateInPlace(ctx, ref, opts);
7532
7527
  });
7533
7528
  return newId2;
7534
7529
  } catch (err) {
@@ -7536,6 +7531,74 @@ function duplicate(ctx, ref, opts = {}) {
7536
7531
  throw err;
7537
7532
  }
7538
7533
  }
7534
+ function duplicateMany(ctx, ids, opts = {}) {
7535
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
7536
+ if (!ordered.length) return [];
7537
+ const snapBefore = ctx.makeSnapshot("duplicateMany:before");
7538
+ try {
7539
+ const created = [];
7540
+ ctx.transact("duplicateMany", () => {
7541
+ var _a, _b, _c;
7542
+ const props = ctx.getProps();
7543
+ const selectedFields = /* @__PURE__ */ new Set();
7544
+ for (const id of ordered) {
7545
+ if (ctx.isFieldId(id) && ((_a = props.fields) != null ? _a : []).some((f) => f.id === id)) {
7546
+ selectedFields.add(id);
7547
+ }
7548
+ }
7549
+ for (const id of ordered) {
7550
+ if (ctx.isTagId(id)) {
7551
+ if (!((_b = ctx.getProps().filters) != null ? _b : []).some((t) => t.id === id)) continue;
7552
+ created.push(
7553
+ duplicateInPlace(ctx, { kind: "tag", id }, opts)
7554
+ );
7555
+ continue;
7556
+ }
7557
+ if (ctx.isFieldId(id)) {
7558
+ if (!((_c = ctx.getProps().fields) != null ? _c : []).some((f) => f.id === id)) continue;
7559
+ created.push(
7560
+ duplicateInPlace(ctx, { kind: "field", id }, opts)
7561
+ );
7562
+ continue;
7563
+ }
7564
+ if (ctx.isOptionId(id)) {
7565
+ const owner = ownerFieldOfOption(ctx.getProps(), id);
7566
+ if (!owner) continue;
7567
+ if (selectedFields.has(owner.fieldId)) continue;
7568
+ created.push(
7569
+ duplicateInPlace(
7570
+ ctx,
7571
+ { kind: "option", fieldId: owner.fieldId, id },
7572
+ opts
7573
+ )
7574
+ );
7575
+ }
7576
+ }
7577
+ });
7578
+ return created;
7579
+ } catch (err) {
7580
+ ctx.loadSnapshot(snapBefore, "undo");
7581
+ throw err;
7582
+ }
7583
+ }
7584
+ function duplicateInPlace(ctx, ref, opts = {}) {
7585
+ if (ref.kind === "tag") {
7586
+ return duplicateTag(ctx, ref.id, opts);
7587
+ }
7588
+ if (ref.kind === "field") {
7589
+ return duplicateField(ctx, ref.id, opts);
7590
+ }
7591
+ return duplicateOption(ctx, ref.fieldId, ref.id, opts);
7592
+ }
7593
+ function ownerFieldOfOption(props, optionId) {
7594
+ var _a, _b;
7595
+ for (const field of (_a = props.fields) != null ? _a : []) {
7596
+ if (((_b = field.options) != null ? _b : []).some((o) => o.id === optionId)) {
7597
+ return { fieldId: field.id };
7598
+ }
7599
+ }
7600
+ return null;
7601
+ }
7539
7602
  function duplicateTag(ctx, tagId, opts) {
7540
7603
  var _a, _b, _c, _d;
7541
7604
  const props = ctx.getProps();
@@ -7822,6 +7885,129 @@ function ensureServiceExists(opts, id) {
7822
7885
  }
7823
7886
 
7824
7887
  // src/react/canvas/editor/editor-nodes.ts
7888
+ var RELATION_MAP_KEYS = [
7889
+ "includes_for_buttons",
7890
+ "excludes_for_buttons",
7891
+ "includes_for_options",
7892
+ "excludes_for_options"
7893
+ ];
7894
+ function stripDeletedIds(ids) {
7895
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
7896
+ return { ordered, set: new Set(ordered) };
7897
+ }
7898
+ function cleanTagRelationsForDeleted(p, deleted) {
7899
+ var _a;
7900
+ for (const t of (_a = p.filters) != null ? _a : []) {
7901
+ if (t.bind_id && deleted.has(String(t.bind_id))) delete t.bind_id;
7902
+ if (t.includes) {
7903
+ const next = t.includes.filter((x) => !deleted.has(String(x)));
7904
+ if (next.length) t.includes = next;
7905
+ else delete t.includes;
7906
+ }
7907
+ if (t.excludes) {
7908
+ const next = t.excludes.filter((x) => !deleted.has(String(x)));
7909
+ if (next.length) t.excludes = next;
7910
+ else delete t.excludes;
7911
+ }
7912
+ }
7913
+ }
7914
+ function cleanFieldBindsForDeleted(p, deleted) {
7915
+ var _a;
7916
+ for (const f of (_a = p.fields) != null ? _a : []) {
7917
+ const bind = f.bind_id;
7918
+ if (!bind) continue;
7919
+ if (Array.isArray(bind)) {
7920
+ const next = bind.filter((x) => !deleted.has(String(x)));
7921
+ if (next.length) f.bind_id = next;
7922
+ else delete f.bind_id;
7923
+ continue;
7924
+ }
7925
+ if (deleted.has(String(bind))) delete f.bind_id;
7926
+ }
7927
+ }
7928
+ function cleanRelationMapsForDeleted(p, deleted) {
7929
+ var _a;
7930
+ for (const key of RELATION_MAP_KEYS) {
7931
+ const map = p[key];
7932
+ if (!map) continue;
7933
+ for (const mapKey of Object.keys(map)) {
7934
+ if (deleted.has(String(mapKey))) {
7935
+ delete map[mapKey];
7936
+ continue;
7937
+ }
7938
+ const next = ((_a = map[mapKey]) != null ? _a : []).filter(
7939
+ (item) => !deleted.has(String(item))
7940
+ );
7941
+ if (next.length) map[mapKey] = next;
7942
+ else delete map[mapKey];
7943
+ }
7944
+ if (!Object.keys(map).length) delete p[key];
7945
+ }
7946
+ }
7947
+ function cleanOrderForTagsForDeleted(p, deleted) {
7948
+ var _a, _b;
7949
+ const map = p.order_for_tags;
7950
+ if (!map) return;
7951
+ const fieldIds = new Set(((_a = p.fields) != null ? _a : []).map((f) => String(f.id)));
7952
+ for (const key of Object.keys(map)) {
7953
+ if (deleted.has(String(key))) {
7954
+ delete map[key];
7955
+ continue;
7956
+ }
7957
+ const next = ((_b = map[key]) != null ? _b : []).filter(
7958
+ (fid) => !deleted.has(String(fid)) && fieldIds.has(String(fid))
7959
+ );
7960
+ if (next.length) map[key] = next;
7961
+ else delete map[key];
7962
+ }
7963
+ if (!Object.keys(map).length) delete p.order_for_tags;
7964
+ }
7965
+ function cleanNoticesForDeleted(p, deleted) {
7966
+ var _a;
7967
+ if (!((_a = p.notices) == null ? void 0 : _a.length)) return;
7968
+ p.notices = p.notices.filter((n) => {
7969
+ const target = n.target;
7970
+ if (!target || target.scope === "global") return true;
7971
+ if (target.scope === "node" && deleted.has(String(target.node_id))) {
7972
+ return false;
7973
+ }
7974
+ return true;
7975
+ });
7976
+ if (!p.notices.length) delete p.notices;
7977
+ }
7978
+ function applyDeleteCleanup(p, deleted) {
7979
+ cleanTagRelationsForDeleted(p, deleted);
7980
+ cleanFieldBindsForDeleted(p, deleted);
7981
+ cleanRelationMapsForDeleted(p, deleted);
7982
+ cleanOrderForTagsForDeleted(p, deleted);
7983
+ cleanNoticesForDeleted(p, deleted);
7984
+ }
7985
+ function removeOptionInPlace(p, optionId) {
7986
+ var _a;
7987
+ const owner = ownerOfOption(p, optionId);
7988
+ if (!owner) return false;
7989
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === owner.fieldId);
7990
+ if (!(f == null ? void 0 : f.options)) return false;
7991
+ const before = f.options.length;
7992
+ f.options = f.options.filter((o) => o.id !== optionId);
7993
+ return f.options.length !== before;
7994
+ }
7995
+ function removeFieldInPlace(p, fieldId) {
7996
+ var _a, _b, _c, _d, _e;
7997
+ const field = ((_a = p.fields) != null ? _a : []).find((f) => f.id === fieldId);
7998
+ if (!field) return [];
7999
+ const deleted = [fieldId, ...((_b = field.options) != null ? _b : []).map((o) => String(o.id))];
8000
+ const before = ((_c = p.fields) != null ? _c : []).length;
8001
+ p.fields = ((_d = p.fields) != null ? _d : []).filter((f) => f.id !== fieldId);
8002
+ clearFieldButtonReceiverMaps(p, fieldId);
8003
+ return ((_e = p.fields) != null ? _e : []).length !== before ? deleted : [];
8004
+ }
8005
+ function removeTagInPlace(p, tagId) {
8006
+ var _a, _b, _c;
8007
+ const before = ((_a = p.filters) != null ? _a : []).length;
8008
+ p.filters = ((_b = p.filters) != null ? _b : []).filter((t) => t.id !== tagId);
8009
+ return ((_c = p.filters) != null ? _c : []).length !== before;
8010
+ }
7825
8011
  function reLabel(ctx, id, nextLabel) {
7826
8012
  const label = String(nextLabel != null ? nextLabel : "").trim();
7827
8013
  ctx.exec({
@@ -7956,22 +8142,9 @@ function removeOption(ctx, optionId) {
7956
8142
  ctx.exec({
7957
8143
  name: "removeOption",
7958
8144
  do: () => ctx.patchProps((p) => {
7959
- var _a;
7960
- const owner = ownerOfOption(p, optionId);
7961
- if (!owner) return;
7962
- const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === owner.fieldId);
7963
- if (!(f == null ? void 0 : f.options)) return;
7964
- f.options = f.options.filter((o) => o.id !== optionId);
7965
- const maps = [
7966
- "includes_for_options",
7967
- "excludes_for_options"
7968
- ];
7969
- for (const m of maps) {
7970
- const map = p[m];
7971
- if (!map) continue;
7972
- if (map[optionId]) delete map[optionId];
7973
- if (!Object.keys(map).length) delete p[m];
7974
- }
8145
+ const removed = removeOptionInPlace(p, optionId);
8146
+ if (!removed) return;
8147
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([optionId]));
7975
8148
  }),
7976
8149
  undo: () => ctx.undo()
7977
8150
  });
@@ -8160,21 +8333,10 @@ function removeTag(ctx, id) {
8160
8333
  ctx.exec({
8161
8334
  name: "removeTag",
8162
8335
  do: () => ctx.patchProps((p) => {
8163
- var _a, _b, _c, _d, _e;
8164
8336
  prevSlice = (0, import_lodash_es3.cloneDeep)(p);
8165
- p.filters = ((_a = p.filters) != null ? _a : []).filter((t) => t.id !== id);
8166
- for (const t of (_b = p.filters) != null ? _b : []) {
8167
- if (t.bind_id === id) delete t.bind_id;
8168
- t.includes = ((_c = t.includes) != null ? _c : []).filter((x) => x !== id);
8169
- t.excludes = ((_d = t.excludes) != null ? _d : []).filter((x) => x !== id);
8170
- }
8171
- for (const f of (_e = p.fields) != null ? _e : []) {
8172
- if (Array.isArray(f.bind_id)) {
8173
- f.bind_id = f.bind_id.filter((x) => x !== id);
8174
- } else if (f.bind_id === id) {
8175
- delete f.bind_id;
8176
- }
8177
- }
8337
+ const removed = removeTagInPlace(p, id);
8338
+ if (!removed) return;
8339
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([id]));
8178
8340
  }),
8179
8341
  undo: () => ctx.replaceProps(prevSlice)
8180
8342
  });
@@ -8242,58 +8404,23 @@ function removeField(ctx, id) {
8242
8404
  ctx.exec({
8243
8405
  name: "removeField",
8244
8406
  do: () => ctx.patchProps((p) => {
8245
- var _a, _b, _c, _d, _e, _f;
8246
8407
  prevSlice = (0, import_lodash_es3.cloneDeep)(p);
8247
- p.fields = ((_a = p.fields) != null ? _a : []).filter((f) => f.id !== id);
8248
- clearFieldButtonReceiverMaps(p, id);
8249
- for (const mapKey of [
8250
- "includes_for_buttons",
8251
- "excludes_for_buttons"
8252
- ]) {
8253
- const m = p[mapKey];
8254
- if (!m) continue;
8255
- for (const k of Object.keys(m)) {
8256
- m[k] = ((_b = m[k]) != null ? _b : []).filter((fid) => fid !== id);
8257
- if (!((_c = m[k]) == null ? void 0 : _c.length)) delete m[k];
8258
- }
8259
- }
8260
- for (const t of (_d = p.filters) != null ? _d : []) {
8261
- t.includes = ((_e = t.includes) != null ? _e : []).filter((x) => x !== id);
8262
- t.excludes = ((_f = t.excludes) != null ? _f : []).filter((x) => x !== id);
8263
- }
8408
+ const removedIds = removeFieldInPlace(p, id);
8409
+ if (!removedIds.length) return;
8410
+ applyDeleteCleanup(p, new Set(removedIds));
8264
8411
  }),
8265
8412
  undo: () => ctx.replaceProps(prevSlice)
8266
8413
  });
8267
8414
  }
8268
8415
  function remove(ctx, id) {
8416
+ const key = String(id);
8269
8417
  if (ctx.isTagId(id)) {
8270
8418
  ctx.exec({
8271
8419
  name: "removeTag",
8272
8420
  do: () => ctx.patchProps((p) => {
8273
- var _a, _b, _c, _d, _e, _f, _g, _h;
8274
- p.filters = ((_a = p.filters) != null ? _a : []).filter((t) => t.id !== id);
8275
- for (const t of (_b = p.filters) != null ? _b : []) {
8276
- if (t.bind_id === id) delete t.bind_id;
8277
- t.includes = ((_c = t.includes) != null ? _c : []).filter((x) => x !== id);
8278
- t.excludes = ((_d = t.excludes) != null ? _d : []).filter((x) => x !== id);
8279
- }
8280
- for (const f of (_e = p.fields) != null ? _e : []) {
8281
- if (Array.isArray(f.bind_id)) {
8282
- f.bind_id = f.bind_id.filter((x) => x !== id);
8283
- } else if (f.bind_id === id) {
8284
- delete f.bind_id;
8285
- }
8286
- }
8287
- if ((_f = p.order_for_tags) == null ? void 0 : _f[id]) delete p.order_for_tags[id];
8288
- for (const k of Object.keys((_g = p.order_for_tags) != null ? _g : {})) {
8289
- p.order_for_tags[k] = ((_h = p.order_for_tags[k]) != null ? _h : []).filter(
8290
- (fid) => {
8291
- var _a2;
8292
- return ((_a2 = p.fields) != null ? _a2 : []).some((f) => f.id === fid);
8293
- }
8294
- );
8295
- if (!p.order_for_tags[k].length) delete p.order_for_tags[k];
8296
- }
8421
+ const removed = removeTagInPlace(p, key);
8422
+ if (!removed) return;
8423
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([key]));
8297
8424
  }),
8298
8425
  undo: () => ctx.undo()
8299
8426
  });
@@ -8303,42 +8430,67 @@ function remove(ctx, id) {
8303
8430
  ctx.exec({
8304
8431
  name: "removeField",
8305
8432
  do: () => ctx.patchProps((p) => {
8306
- var _a, _b, _c, _d, _e, _f, _g, _h;
8307
- p.fields = ((_a = p.fields) != null ? _a : []).filter((f) => f.id !== id);
8308
- for (const t of (_b = p.filters) != null ? _b : []) {
8309
- t.includes = ((_c = t.includes) != null ? _c : []).filter((x) => x !== id);
8310
- t.excludes = ((_d = t.excludes) != null ? _d : []).filter((x) => x !== id);
8311
- }
8312
- for (const k of Object.keys((_e = p.order_for_tags) != null ? _e : {})) {
8313
- p.order_for_tags[k] = ((_f = p.order_for_tags[k]) != null ? _f : []).filter(
8314
- (fid) => fid !== id
8315
- );
8316
- if (!p.order_for_tags[k].length) delete p.order_for_tags[k];
8317
- }
8318
- const maps = [
8319
- "includes_for_options",
8320
- "excludes_for_options"
8321
- ];
8322
- for (const m of maps) {
8323
- const map = p[m];
8324
- if (!map) continue;
8325
- for (const key of Object.keys(map)) {
8326
- map[key] = ((_g = map[key]) != null ? _g : []).filter((fid) => fid !== id);
8327
- if (!((_h = map[key]) == null ? void 0 : _h.length)) delete map[key];
8328
- }
8329
- if (!Object.keys(map).length) delete p[m];
8330
- }
8433
+ const removedIds = removeFieldInPlace(p, key);
8434
+ if (!removedIds.length) return;
8435
+ applyDeleteCleanup(p, new Set(removedIds));
8331
8436
  }),
8332
8437
  undo: () => ctx.undo()
8333
8438
  });
8334
8439
  return;
8335
8440
  }
8336
8441
  if (ctx.isOptionId(id)) {
8337
- removeOption(ctx, id);
8442
+ ctx.exec({
8443
+ name: "removeOption",
8444
+ do: () => ctx.patchProps((p) => {
8445
+ const removed = removeOptionInPlace(p, key);
8446
+ if (!removed) return;
8447
+ applyDeleteCleanup(p, /* @__PURE__ */ new Set([key]));
8448
+ }),
8449
+ undo: () => ctx.undo()
8450
+ });
8338
8451
  return;
8339
8452
  }
8340
8453
  throw new Error("remove: unknown id prefix");
8341
8454
  }
8455
+ function removeMany(ctx, ids) {
8456
+ const { ordered } = stripDeletedIds(ids);
8457
+ if (!ordered.length) return;
8458
+ ctx.transact("removeMany", () => {
8459
+ ctx.patchProps((p) => {
8460
+ var _a, _b, _c;
8461
+ const existingFieldIds = new Set(((_a = p.fields) != null ? _a : []).map((f) => String(f.id)));
8462
+ const existingTagIds = new Set(((_b = p.filters) != null ? _b : []).map((t) => String(t.id)));
8463
+ const existingOptionIds = new Set(
8464
+ ((_c = p.fields) != null ? _c : []).flatMap((f) => {
8465
+ var _a2;
8466
+ return ((_a2 = f.options) != null ? _a2 : []).map((o) => String(o.id));
8467
+ })
8468
+ );
8469
+ const fieldIds = ordered.filter((id) => ctx.isFieldId(id) && existingFieldIds.has(id));
8470
+ const fieldIdSet = new Set(fieldIds);
8471
+ const tagIds = ordered.filter((id) => ctx.isTagId(id) && existingTagIds.has(id));
8472
+ const optionIds = ordered.filter((id) => {
8473
+ if (!ctx.isOptionId(id) || !existingOptionIds.has(id)) return false;
8474
+ const owner = ownerOfOption(p, id);
8475
+ if (!owner) return false;
8476
+ return !fieldIdSet.has(String(owner.fieldId));
8477
+ });
8478
+ const deleted = /* @__PURE__ */ new Set();
8479
+ for (const optionId of optionIds) {
8480
+ if (removeOptionInPlace(p, optionId)) deleted.add(optionId);
8481
+ }
8482
+ for (const fieldId of fieldIds) {
8483
+ const removedIds = removeFieldInPlace(p, fieldId);
8484
+ for (const rid of removedIds) deleted.add(rid);
8485
+ }
8486
+ for (const tagId of tagIds) {
8487
+ if (removeTagInPlace(p, tagId)) deleted.add(tagId);
8488
+ }
8489
+ if (!deleted.size) return;
8490
+ applyDeleteCleanup(p, deleted);
8491
+ });
8492
+ });
8493
+ }
8342
8494
  function getNode(ctx, id) {
8343
8495
  var _a, _b, _c, _d;
8344
8496
  const props = ctx.getProps();
@@ -9583,6 +9735,9 @@ var Editor = class {
9583
9735
  duplicate(ref, opts = {}) {
9584
9736
  return duplicate(this.moduleCtx(), ref, opts);
9585
9737
  }
9738
+ duplicateMany(ids, opts = {}) {
9739
+ return duplicateMany(this.moduleCtx(), ids, opts);
9740
+ }
9586
9741
  reLabel(id, nextLabel) {
9587
9742
  return reLabel(this.moduleCtx(), id, nextLabel);
9588
9743
  }
@@ -9646,6 +9801,260 @@ var Editor = class {
9646
9801
  remove(id) {
9647
9802
  return remove(this.moduleCtx(), id);
9648
9803
  }
9804
+ removeMany(ids) {
9805
+ return removeMany(this.moduleCtx(), ids);
9806
+ }
9807
+ clearServiceMany(ids) {
9808
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9809
+ if (!ordered.length) return;
9810
+ this.transact("clearServiceMany", () => {
9811
+ this.patchProps((p) => {
9812
+ var _a, _b, _c, _d;
9813
+ for (const id of ordered) {
9814
+ if (this.isTagId(id)) {
9815
+ const t = ((_a = p.filters) != null ? _a : []).find((x) => x.id === id);
9816
+ if (t && "service_id" in t) delete t.service_id;
9817
+ continue;
9818
+ }
9819
+ if (this.isFieldId(id)) {
9820
+ const f = ((_b = p.fields) != null ? _b : []).find((x) => x.id === id);
9821
+ if (f && "service_id" in f) delete f.service_id;
9822
+ continue;
9823
+ }
9824
+ if (this.isOptionId(id)) {
9825
+ const own = ownerOfOption(p, id);
9826
+ if (!own) continue;
9827
+ const f = ((_c = p.fields) != null ? _c : []).find((x) => x.id === own.fieldId);
9828
+ const o = (_d = f == null ? void 0 : f.options) == null ? void 0 : _d.find((x) => x.id === id);
9829
+ if (o && "service_id" in o) delete o.service_id;
9830
+ }
9831
+ }
9832
+ });
9833
+ });
9834
+ }
9835
+ rebindMany(ids, targetTagId, opts) {
9836
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9837
+ if (!ordered.length) return;
9838
+ this.transact("rebindMany", () => {
9839
+ this.patchProps((p) => {
9840
+ var _a, _b, _c;
9841
+ const targetExists = ((_a = p.filters) != null ? _a : []).some((t) => t.id === targetTagId);
9842
+ if (!targetExists) return;
9843
+ for (const id of ordered) {
9844
+ if (this.isFieldId(id)) {
9845
+ const f = ((_b = p.fields) != null ? _b : []).find((x) => x.id === id);
9846
+ if (!f) continue;
9847
+ f.bind_id = targetTagId;
9848
+ continue;
9849
+ }
9850
+ if (this.isTagId(id)) {
9851
+ const t = ((_c = p.filters) != null ? _c : []).find((x) => x.id === id);
9852
+ if (!t) continue;
9853
+ if (!(opts == null ? void 0 : opts.allowTagCycles) && wouldCreateTagCycle(this.moduleCtx(), p, targetTagId, id)) {
9854
+ continue;
9855
+ }
9856
+ t.bind_id = targetTagId;
9857
+ }
9858
+ }
9859
+ });
9860
+ });
9861
+ }
9862
+ includeMany(receiverId, ids) {
9863
+ const accepted = Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))).filter((id) => id !== receiverId).filter((id) => this.getNode(id).data != null);
9864
+ if (!accepted.length) return;
9865
+ include(this.moduleCtx(), receiverId, accepted);
9866
+ }
9867
+ excludeMany(receiverId, ids) {
9868
+ const accepted = Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))).filter((id) => id !== receiverId).filter((id) => this.getNode(id).data != null);
9869
+ if (!accepted.length) return;
9870
+ exclude(this.moduleCtx(), receiverId, accepted);
9871
+ }
9872
+ clearRelationsMany(ids, mode = "both") {
9873
+ const selected = new Set(Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))));
9874
+ if (!selected.size) return;
9875
+ this.transact("clearRelationsMany", () => {
9876
+ this.patchProps((p) => {
9877
+ var _a, _b, _c;
9878
+ const clearOwned = mode === "owned" || mode === "both";
9879
+ const clearIncoming = mode === "incoming" || mode === "both";
9880
+ for (const t of (_a = p.filters) != null ? _a : []) {
9881
+ if (clearOwned && selected.has(t.id)) {
9882
+ delete t.includes;
9883
+ delete t.excludes;
9884
+ }
9885
+ if (clearIncoming) {
9886
+ if (t.includes) {
9887
+ t.includes = t.includes.filter((x) => !selected.has(String(x)));
9888
+ if (!t.includes.length) delete t.includes;
9889
+ }
9890
+ if (t.excludes) {
9891
+ t.excludes = t.excludes.filter((x) => !selected.has(String(x)));
9892
+ if (!t.excludes.length) delete t.excludes;
9893
+ }
9894
+ }
9895
+ }
9896
+ const maps = [
9897
+ "includes_for_buttons",
9898
+ "excludes_for_buttons",
9899
+ "includes_for_options",
9900
+ "excludes_for_options"
9901
+ ];
9902
+ for (const k of maps) {
9903
+ const map = p[k];
9904
+ if (!map) continue;
9905
+ for (const key of Object.keys(map)) {
9906
+ if (clearOwned && selected.has(String(key))) {
9907
+ delete map[key];
9908
+ continue;
9909
+ }
9910
+ if (clearIncoming) {
9911
+ map[key] = ((_b = map[key]) != null ? _b : []).filter((x) => !selected.has(String(x)));
9912
+ if (!((_c = map[key]) == null ? void 0 : _c.length)) delete map[key];
9913
+ }
9914
+ }
9915
+ if (!Object.keys(map).length) delete p[k];
9916
+ }
9917
+ });
9918
+ });
9919
+ }
9920
+ renameLabelsMany(ids, input) {
9921
+ var _a, _b;
9922
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9923
+ if (!ordered.length) return;
9924
+ const prefix = (_a = input.prefix) != null ? _a : "";
9925
+ const suffix = (_b = input.suffix) != null ? _b : "";
9926
+ this.transact("renameLabelsMany", () => {
9927
+ this.patchProps((p) => {
9928
+ var _a2, _b2, _c, _d, _e, _f, _g;
9929
+ for (const id of ordered) {
9930
+ if (this.isTagId(id)) {
9931
+ const t = ((_a2 = p.filters) != null ? _a2 : []).find((x) => x.id === id);
9932
+ if (t) t.label = `${prefix}${(_b2 = t.label) != null ? _b2 : ""}${suffix}`.trim();
9933
+ continue;
9934
+ }
9935
+ if (this.isFieldId(id)) {
9936
+ const f = ((_c = p.fields) != null ? _c : []).find((x) => x.id === id);
9937
+ if (f) f.label = `${prefix}${(_d = f.label) != null ? _d : ""}${suffix}`.trim();
9938
+ continue;
9939
+ }
9940
+ if (this.isOptionId(id)) {
9941
+ const own = ownerOfOption(p, id);
9942
+ if (!own) continue;
9943
+ const f = ((_e = p.fields) != null ? _e : []).find((x) => x.id === own.fieldId);
9944
+ const o = (_f = f == null ? void 0 : f.options) == null ? void 0 : _f.find((x) => x.id === id);
9945
+ if (o) o.label = `${prefix}${(_g = o.label) != null ? _g : ""}${suffix}`.trim();
9946
+ }
9947
+ }
9948
+ });
9949
+ });
9950
+ }
9951
+ setPricingRoleMany(ids, role) {
9952
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9953
+ if (!ordered.length) return;
9954
+ this.transact("setPricingRoleMany", () => {
9955
+ for (const id of ordered) {
9956
+ if (this.isFieldId(id) || this.isOptionId(id)) {
9957
+ this.setService(id, { pricing_role: role });
9958
+ }
9959
+ }
9960
+ });
9961
+ }
9962
+ clearFieldDefaultsMany(ids) {
9963
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9964
+ if (!ordered.length) return;
9965
+ this.transact("clearFieldDefaultsMany", () => {
9966
+ this.patchProps((p) => {
9967
+ var _a;
9968
+ for (const id of ordered) {
9969
+ if (!this.isFieldId(id)) continue;
9970
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === id);
9971
+ if (f && "defaults" in f) delete f.defaults;
9972
+ }
9973
+ });
9974
+ });
9975
+ }
9976
+ clearFieldValidationMany(ids) {
9977
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9978
+ if (!ordered.length) return;
9979
+ this.transact("clearFieldValidationMany", () => {
9980
+ this.patchProps((p) => {
9981
+ var _a;
9982
+ for (const id of ordered) {
9983
+ if (!this.isFieldId(id)) continue;
9984
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === id);
9985
+ if (f && "validation" in f) delete f.validation;
9986
+ }
9987
+ });
9988
+ });
9989
+ }
9990
+ autoCreateOptionsMany(ids, makeOption) {
9991
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9992
+ if (!ordered.length) return;
9993
+ this.transact("autoCreateOptionsMany", () => {
9994
+ this.patchProps((p) => {
9995
+ var _a, _b, _c, _d;
9996
+ for (const id of ordered) {
9997
+ if (!this.isFieldId(id)) continue;
9998
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === id);
9999
+ if (!f) continue;
10000
+ const opts = (_b = f.options) != null ? _b : f.options = [];
10001
+ if (opts.length > 0) continue;
10002
+ const next = (_c = makeOption == null ? void 0 : makeOption(id)) != null ? _c : { label: "Option label", value: "option" };
10003
+ opts.push({
10004
+ id: (_d = next.id) != null ? _d : this.moduleCtx().genId("o"),
10005
+ label: next.label,
10006
+ value: next.value
10007
+ });
10008
+ }
10009
+ });
10010
+ });
10011
+ }
10012
+ clearAllOptionsMany(ids) {
10013
+ var _a, _b;
10014
+ const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
10015
+ if (!ordered.length) return;
10016
+ const optionIds = [];
10017
+ const props = this.getProps();
10018
+ for (const id of ordered) {
10019
+ if (!this.isFieldId(id)) continue;
10020
+ const f = ((_a = props.fields) != null ? _a : []).find((x) => x.id === id);
10021
+ for (const o of (_b = f == null ? void 0 : f.options) != null ? _b : []) optionIds.push(o.id);
10022
+ }
10023
+ if (!optionIds.length) return;
10024
+ removeMany(this.moduleCtx(), optionIds);
10025
+ }
10026
+ removeNoticesForNodes(ids) {
10027
+ const selected = new Set(Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))));
10028
+ if (!selected.size) return;
10029
+ this.transact("removeNoticesForNodes", () => {
10030
+ this.patchProps((p) => {
10031
+ var _a;
10032
+ if (!((_a = p.notices) == null ? void 0 : _a.length)) return;
10033
+ p.notices = p.notices.filter((n) => {
10034
+ const target = n.target;
10035
+ if (!target || target.scope === "global") return true;
10036
+ if (target.scope === "node") return !selected.has(String(target.node_id));
10037
+ return true;
10038
+ });
10039
+ if (!p.notices.length) delete p.notices;
10040
+ });
10041
+ });
10042
+ }
10043
+ setNoticesVisibilityForNodes(ids, type) {
10044
+ const selected = new Set(Array.from(new Set((ids != null ? ids : []).map((id) => String(id)))));
10045
+ if (!selected.size) return;
10046
+ this.transact("setNoticesVisibilityForNodes", () => {
10047
+ this.patchProps((p) => {
10048
+ var _a;
10049
+ for (const n of (_a = p.notices) != null ? _a : []) {
10050
+ const target = n.target;
10051
+ if ((target == null ? void 0 : target.scope) === "node" && selected.has(String(target.node_id))) {
10052
+ n.type = type;
10053
+ }
10054
+ }
10055
+ });
10056
+ });
10057
+ }
9649
10058
  getNode(id) {
9650
10059
  return getNode(this.moduleCtx(), id);
9651
10060
  }
@@ -9889,9 +10298,8 @@ var Editor = class {
9889
10298
  Array.isArray(canvas.selection) ? canvas.selection : Array.from(canvas.selection)
9890
10299
  );
9891
10300
  }
9892
- } else {
9893
- this.api.refreshGraph();
9894
10301
  }
10302
+ this.api.refreshGraph();
9895
10303
  this.emit("editor:change", { props: s.props, reason, snapshot: s });
9896
10304
  }
9897
10305
  pushHistory(snap) {
@@ -10979,12 +11387,12 @@ function useCanvasOwned(initialProps, canvasOpts, builderOpts) {
10979
11387
  // src/react/workspace/context/hooks/use-canvas.ts
10980
11388
  var React16 = __toESM(require("react"), 1);
10981
11389
  var import_react4 = require("react");
10982
- function deriveSelectionInfo(props, ids) {
11390
+ function deriveSelectionInfo(nodeMap, ids) {
10983
11391
  const tags = [];
10984
11392
  const fields = [];
10985
11393
  const options = [];
10986
11394
  for (const id of ids) {
10987
- const node = props.get(id);
11395
+ const node = nodeMap.get(id);
10988
11396
  if (!node) continue;
10989
11397
  if (node.kind == "tag") {
10990
11398
  tags.push(id);
@@ -11011,6 +11419,49 @@ function deriveSelectionInfo(props, ids) {
11011
11419
  optionIds: uniq2(options)
11012
11420
  };
11013
11421
  }
11422
+ function noticeTargetsSelection(notice, selected) {
11423
+ const target = notice.target;
11424
+ if (target.scope === "global") return false;
11425
+ return selected.has(String(target.node_id));
11426
+ }
11427
+ function deriveSelectionCapabilities(props, selectionInfo) {
11428
+ var _a, _b, _c;
11429
+ const selected = new Set(selectionInfo.ids.map(String));
11430
+ const fields = (_a = props == null ? void 0 : props.fields) != null ? _a : [];
11431
+ const tags = (_b = props == null ? void 0 : props.filters) != null ? _b : [];
11432
+ const notices = (_c = props == null ? void 0 : props.notices) != null ? _c : [];
11433
+ const hasSelectedFieldWithOptions = fields.some(
11434
+ (f) => {
11435
+ var _a2, _b2;
11436
+ return selected.has(String(f.id)) && ((_b2 = (_a2 = f.options) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0;
11437
+ }
11438
+ );
11439
+ const hasServiceBearingNodes = tags.some(
11440
+ (t) => selected.has(String(t.id)) && t.service_id !== void 0 && t.service_id !== null
11441
+ ) || fields.some(
11442
+ (f) => selected.has(String(f.id)) && f.service_id !== void 0 && f.service_id !== null
11443
+ ) || fields.some(
11444
+ (f) => {
11445
+ var _a2;
11446
+ return ((_a2 = f.options) != null ? _a2 : []).some(
11447
+ (o) => selected.has(String(o.id)) && o.service_id !== void 0 && o.service_id !== null
11448
+ );
11449
+ }
11450
+ );
11451
+ const hasNoticesForSelection = notices.some(
11452
+ (n) => noticeTargetsSelection(n, selected)
11453
+ );
11454
+ return {
11455
+ hasTags: selectionInfo.tagIds.length > 0,
11456
+ hasFields: selectionInfo.fieldIds.length > 0,
11457
+ hasOptions: selectionInfo.optionIds.length > 0,
11458
+ hasServiceBearingNodes,
11459
+ hasSelectedFieldWithOptions,
11460
+ hasNoticesForSelection,
11461
+ canIncludeExcludeTargets: selectionInfo.tagIds.length + selectionInfo.fieldIds.length + selectionInfo.optionIds.length > 0,
11462
+ canRebind: selectionInfo.fieldIds.length > 0 || selectionInfo.tagIds.length > 0
11463
+ };
11464
+ }
11014
11465
  function tagBindIds(tag) {
11015
11466
  const bind = tag.bind_id;
11016
11467
  if (!bind) return [];
@@ -11150,7 +11601,11 @@ function useCanvas() {
11150
11601
  });
11151
11602
  return off;
11152
11603
  }, [api]);
11153
- const selector = (0, import_react4.useMemo)(() => createNodeIndex(api.builder), [props]);
11604
+ const selector = (0, import_react4.useMemo)(() => createNodeIndex(api.builder), [api.builder, props]);
11605
+ const selectionCapabilities = React16.useMemo(
11606
+ () => deriveSelectionCapabilities(props, selectionInfo),
11607
+ [props, selectionInfo]
11608
+ );
11154
11609
  return React16.useMemo(
11155
11610
  () => ({
11156
11611
  api,
@@ -11159,6 +11614,7 @@ function useCanvas() {
11159
11614
  props,
11160
11615
  selection,
11161
11616
  selectionInfo,
11617
+ selectionCapabilities,
11162
11618
  selector,
11163
11619
  activeId,
11164
11620
  setActive
@@ -11170,6 +11626,7 @@ function useCanvas() {
11170
11626
  props,
11171
11627
  selection,
11172
11628
  selectionInfo,
11629
+ selectionCapabilities,
11173
11630
  selector,
11174
11631
  activeId,
11175
11632
  setActive
@@ -13857,6 +14314,7 @@ var import_jsx_runtime11 = require("react/jsx-runtime");
13857
14314
  WorkspaceProvider,
13858
14315
  createMemoryWorkspaceBackend,
13859
14316
  createPollAdapter,
14317
+ deriveSelectionCapabilities,
13860
14318
  useCanvas,
13861
14319
  useCanvasAPI,
13862
14320
  useCanvasFromBuilder,