@routevn/creator-model 1.7.3 → 1.8.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/model.js +519 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routevn/creator-model",
3
- "version": "1.7.3",
3
+ "version": "1.8.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/model.js CHANGED
@@ -392,7 +392,7 @@ const LAYOUT_ELEMENT_BASE_TYPES = [
392
392
  "container-ref-confirm-dialog-ok",
393
393
  "container-ref-confirm-dialog-cancel",
394
394
  ];
395
- export const SCHEMA_VERSION = 7;
395
+ export const SCHEMA_VERSION = 8;
396
396
  const LAYOUT_CONTAINER_ELEMENT_TYPES = [
397
397
  "folder",
398
398
  "container",
@@ -404,6 +404,18 @@ const LAYOUT_CONTAINER_ELEMENT_TYPES = [
404
404
  "container-ref-confirm-dialog-ok",
405
405
  "container-ref-confirm-dialog-cancel",
406
406
  ];
407
+ const LAYOUT_TEXT_CONTENT_ELEMENT_TYPES = [
408
+ "text",
409
+ "text-revealing",
410
+ "text-ref-character-name",
411
+ "text-revealing-ref-dialogue-content",
412
+ "text-ref-choice-item-content",
413
+ "text-ref-save-load-slot-date",
414
+ "text-ref-dialogue-line-character-name",
415
+ "text-ref-dialogue-line-content",
416
+ "text-ref-history-line-character-name",
417
+ "text-ref-history-line-content",
418
+ ];
407
419
  const DOMAIN_ERROR_KIND_BY_NAME = {
408
420
  PayloadValidationError: "payload",
409
421
  PreconditionValidationError: "precondition",
@@ -3419,6 +3431,251 @@ const validateLayoutElementBlur = ({ blur, path, errorFactory }) => {
3419
3431
  }
3420
3432
  };
3421
3433
 
3434
+ const LAYOUT_TEXT_REVEAL_INDICATOR_ELEMENT_TYPES = [
3435
+ "text-revealing",
3436
+ "text-revealing-ref-dialogue-content",
3437
+ ];
3438
+
3439
+ const validateLayoutTextRevealIndicatorVisual = ({
3440
+ visual,
3441
+ path,
3442
+ errorFactory,
3443
+ }) => {
3444
+ if (!isPlainObject(visual)) {
3445
+ return invalidFromErrorFactory(
3446
+ errorFactory,
3447
+ `${path} must be an object when provided`,
3448
+ );
3449
+ }
3450
+
3451
+ {
3452
+ const result = validateAllowedKeys({
3453
+ value: visual,
3454
+ allowedKeys: [
3455
+ "kind",
3456
+ "imageId",
3457
+ "resourceId",
3458
+ "animationName",
3459
+ "width",
3460
+ "height",
3461
+ "offsetX",
3462
+ "offsetY",
3463
+ ],
3464
+ path,
3465
+ errorFactory,
3466
+ });
3467
+ if (result?.valid === false) {
3468
+ return result;
3469
+ }
3470
+ }
3471
+
3472
+ const kind =
3473
+ visual.kind === "spritesheet" ||
3474
+ visual.resourceId !== undefined ||
3475
+ visual.animationName !== undefined
3476
+ ? "spritesheet"
3477
+ : "image";
3478
+
3479
+ if (
3480
+ visual.kind !== undefined &&
3481
+ visual.kind !== "image" &&
3482
+ visual.kind !== "spritesheet"
3483
+ ) {
3484
+ return invalidFromErrorFactory(
3485
+ errorFactory,
3486
+ `${path}.kind must be 'image' or 'spritesheet' when provided`,
3487
+ );
3488
+ }
3489
+
3490
+ if (kind === "image" && !isNonEmptyString(visual.imageId)) {
3491
+ return invalidFromErrorFactory(
3492
+ errorFactory,
3493
+ `${path}.imageId must be a non-empty string`,
3494
+ );
3495
+ }
3496
+
3497
+ if (kind === "spritesheet") {
3498
+ if (!isNonEmptyString(visual.resourceId)) {
3499
+ return invalidFromErrorFactory(
3500
+ errorFactory,
3501
+ `${path}.resourceId must be a non-empty string`,
3502
+ );
3503
+ }
3504
+
3505
+ if (!isNonEmptyString(visual.animationName)) {
3506
+ return invalidFromErrorFactory(
3507
+ errorFactory,
3508
+ `${path}.animationName must be a non-empty string`,
3509
+ );
3510
+ }
3511
+ }
3512
+
3513
+ for (const key of ["width", "height"]) {
3514
+ if (
3515
+ visual[key] !== undefined &&
3516
+ (!isFiniteNumber(visual[key]) || visual[key] <= 0)
3517
+ ) {
3518
+ return invalidFromErrorFactory(
3519
+ errorFactory,
3520
+ `${path}.${key} must be a finite number greater than 0 when provided`,
3521
+ );
3522
+ }
3523
+ }
3524
+
3525
+ for (const key of ["offsetX", "offsetY"]) {
3526
+ if (visual[key] !== undefined && !isFiniteNumber(visual[key])) {
3527
+ return invalidFromErrorFactory(
3528
+ errorFactory,
3529
+ `${path}.${key} must be a finite number when provided`,
3530
+ );
3531
+ }
3532
+ }
3533
+ };
3534
+
3535
+ const validateLayoutTextRevealIndicator = ({
3536
+ indicator,
3537
+ path,
3538
+ errorFactory,
3539
+ }) => {
3540
+ if (!isPlainObject(indicator)) {
3541
+ return invalidFromErrorFactory(
3542
+ errorFactory,
3543
+ `${path} must be an object when provided`,
3544
+ );
3545
+ }
3546
+
3547
+ {
3548
+ const result = validateAllowedKeys({
3549
+ value: indicator,
3550
+ allowedKeys: ["revealing", "complete", "offsetX", "offsetY"],
3551
+ path,
3552
+ errorFactory,
3553
+ });
3554
+ if (result?.valid === false) {
3555
+ return result;
3556
+ }
3557
+ }
3558
+
3559
+ for (const key of ["revealing", "complete"]) {
3560
+ if (indicator[key] !== undefined) {
3561
+ const result = validateLayoutTextRevealIndicatorVisual({
3562
+ visual: indicator[key],
3563
+ path: `${path}.${key}`,
3564
+ errorFactory,
3565
+ });
3566
+ if (result?.valid === false) {
3567
+ return result;
3568
+ }
3569
+ }
3570
+ }
3571
+
3572
+ for (const key of ["offsetX", "offsetY"]) {
3573
+ if (indicator[key] !== undefined && !isFiniteNumber(indicator[key])) {
3574
+ return invalidFromErrorFactory(
3575
+ errorFactory,
3576
+ `${path}.${key} must be a finite number when provided`,
3577
+ );
3578
+ }
3579
+ }
3580
+ };
3581
+
3582
+ const validateLayoutTextContent = ({ content, path, errorFactory }) => {
3583
+ if (!Array.isArray(content)) {
3584
+ return invalidFromErrorFactory(
3585
+ errorFactory,
3586
+ `${path} must be an array when provided`,
3587
+ );
3588
+ }
3589
+
3590
+ for (let index = 0; index < content.length; index += 1) {
3591
+ const item = content[index];
3592
+ const itemPath = `${path}[${index}]`;
3593
+
3594
+ if (!isPlainObject(item)) {
3595
+ return invalidFromErrorFactory(
3596
+ errorFactory,
3597
+ `${itemPath} must be an object`,
3598
+ );
3599
+ }
3600
+
3601
+ {
3602
+ const result = validateAllowedKeys({
3603
+ value: item,
3604
+ allowedKeys: ["text", "reference"],
3605
+ path: itemPath,
3606
+ errorFactory,
3607
+ });
3608
+ if (result?.valid === false) {
3609
+ return result;
3610
+ }
3611
+ }
3612
+
3613
+ const hasText = Object.hasOwn(item, "text");
3614
+ const hasReference = Object.hasOwn(item, "reference");
3615
+
3616
+ if (hasText === hasReference) {
3617
+ return invalidFromErrorFactory(
3618
+ errorFactory,
3619
+ `${itemPath} must include exactly one of text or reference`,
3620
+ );
3621
+ }
3622
+
3623
+ if (hasText) {
3624
+ if (!isString(item.text)) {
3625
+ return invalidFromErrorFactory(
3626
+ errorFactory,
3627
+ `${itemPath}.text must be a string`,
3628
+ );
3629
+ }
3630
+ continue;
3631
+ }
3632
+
3633
+ if (!isPlainObject(item.reference)) {
3634
+ return invalidFromErrorFactory(
3635
+ errorFactory,
3636
+ `${itemPath}.reference must be an object`,
3637
+ );
3638
+ }
3639
+
3640
+ {
3641
+ const result = validateAllowedKeys({
3642
+ value: item.reference,
3643
+ allowedKeys: ["resourceId"],
3644
+ path: `${itemPath}.reference`,
3645
+ errorFactory,
3646
+ });
3647
+ if (result?.valid === false) {
3648
+ return result;
3649
+ }
3650
+ }
3651
+
3652
+ if (!isNonEmptyString(item.reference.resourceId)) {
3653
+ return invalidFromErrorFactory(
3654
+ errorFactory,
3655
+ `${itemPath}.reference.resourceId must be a non-empty string`,
3656
+ );
3657
+ }
3658
+ }
3659
+ };
3660
+
3661
+ const getLayoutTextContentReferenceEntries = (content) => {
3662
+ if (!Array.isArray(content)) {
3663
+ return [];
3664
+ }
3665
+
3666
+ const entries = [];
3667
+ for (let index = 0; index < content.length; index += 1) {
3668
+ const resourceId = content[index]?.reference?.resourceId;
3669
+ if (resourceId !== undefined) {
3670
+ entries.push({
3671
+ index,
3672
+ resourceId,
3673
+ });
3674
+ }
3675
+ }
3676
+ return entries;
3677
+ };
3678
+
3422
3679
  const validateLayoutElementData = ({
3423
3680
  data,
3424
3681
  path,
@@ -3447,9 +3704,11 @@ const validateLayoutElementData = ({
3447
3704
  "fill",
3448
3705
  "border",
3449
3706
  "text",
3707
+ "content",
3450
3708
  "textStyle",
3451
3709
  "displaySpeed",
3452
3710
  "revealEffect",
3711
+ "indicator",
3453
3712
  "resourceId",
3454
3713
  "animationName",
3455
3714
  "imageId",
@@ -3628,6 +3887,52 @@ const validateLayoutElementData = ({
3628
3887
  }
3629
3888
  }
3630
3889
 
3890
+ if (data.content !== undefined) {
3891
+ {
3892
+ const result = validateLayoutTextContent({
3893
+ content: data.content,
3894
+ path: `${path}.content`,
3895
+ errorFactory,
3896
+ });
3897
+ if (result?.valid === false) {
3898
+ return result;
3899
+ }
3900
+ }
3901
+
3902
+ if (
3903
+ data.type !== undefined &&
3904
+ !LAYOUT_TEXT_CONTENT_ELEMENT_TYPES.includes(data.type)
3905
+ ) {
3906
+ return invalidFromErrorFactory(
3907
+ errorFactory,
3908
+ `${path}.content can only be provided for text elements`,
3909
+ );
3910
+ }
3911
+ }
3912
+
3913
+ if (data.indicator !== undefined) {
3914
+ {
3915
+ const result = validateLayoutTextRevealIndicator({
3916
+ indicator: data.indicator,
3917
+ path: `${path}.indicator`,
3918
+ errorFactory,
3919
+ });
3920
+ if (result?.valid === false) {
3921
+ return result;
3922
+ }
3923
+ }
3924
+
3925
+ if (
3926
+ data.type !== undefined &&
3927
+ !LAYOUT_TEXT_REVEAL_INDICATOR_ELEMENT_TYPES.includes(data.type)
3928
+ ) {
3929
+ return invalidFromErrorFactory(
3930
+ errorFactory,
3931
+ `${path}.indicator can only be provided for text revealing elements`,
3932
+ );
3933
+ }
3934
+ }
3935
+
3631
3936
  for (const key of [
3632
3937
  "text",
3633
3938
  "resourceId",
@@ -4143,9 +4448,11 @@ const validateLayoutElementItems = ({ items, path, errorFactory }) => {
4143
4448
  "fill",
4144
4449
  "border",
4145
4450
  "text",
4451
+ "content",
4146
4452
  "textStyle",
4147
4453
  "displaySpeed",
4148
4454
  "revealEffect",
4455
+ "indicator",
4149
4456
  "resourceId",
4150
4457
  "animationName",
4151
4458
  "particleId",
@@ -7420,15 +7727,16 @@ export const assertInvariants = ({ state }) => {
7420
7727
  elementId,
7421
7728
  targetId,
7422
7729
  animationName,
7730
+ fieldPrefix = "",
7423
7731
  }) => {
7424
7732
  const spritesheet = state.spritesheets?.items?.[targetId];
7425
7733
  if (!isPlainObject(spritesheet) || spritesheet.type === "folder") {
7426
7734
  return invalidInvariant(
7427
- `${ownerLabel} element resourceId must reference an existing non-folder spritesheet`,
7735
+ `${ownerLabel} element ${fieldPrefix}resourceId must reference an existing non-folder spritesheet`,
7428
7736
  {
7429
7737
  [ownerIdField]: ownerId,
7430
7738
  elementId,
7431
- field: "resourceId",
7739
+ field: `${fieldPrefix}resourceId`,
7432
7740
  targetId,
7433
7741
  },
7434
7742
  );
@@ -7439,11 +7747,11 @@ export const assertInvariants = ({ state }) => {
7439
7747
  !isPlainObject(spritesheet.animations?.[animationName])
7440
7748
  ) {
7441
7749
  return invalidInvariant(
7442
- `${ownerLabel} element animationName must reference an existing spritesheet animation`,
7750
+ `${ownerLabel} element ${fieldPrefix}animationName must reference an existing spritesheet animation`,
7443
7751
  {
7444
7752
  [ownerIdField]: ownerId,
7445
7753
  elementId,
7446
- field: "animationName",
7754
+ field: `${fieldPrefix}animationName`,
7447
7755
  targetId: animationName,
7448
7756
  },
7449
7757
  );
@@ -7542,6 +7850,43 @@ export const assertInvariants = ({ state }) => {
7542
7850
  }
7543
7851
  }
7544
7852
 
7853
+ for (const stateName of ["revealing", "complete"]) {
7854
+ const visual = element.indicator?.[stateName];
7855
+ if (
7856
+ visual?.kind === "spritesheet" ||
7857
+ visual?.resourceId !== undefined ||
7858
+ visual?.animationName !== undefined
7859
+ ) {
7860
+ const result = assertSpritesheetAnimationReference({
7861
+ ownerIdField,
7862
+ ownerId,
7863
+ ownerLabel,
7864
+ elementId,
7865
+ targetId: visual.resourceId,
7866
+ animationName: visual.animationName,
7867
+ fieldPrefix: `indicator.${stateName}.`,
7868
+ });
7869
+ if (!result.valid) {
7870
+ return result;
7871
+ }
7872
+ continue;
7873
+ }
7874
+
7875
+ if (visual?.imageId !== undefined) {
7876
+ const result = assertImageReference({
7877
+ ownerIdField,
7878
+ ownerId,
7879
+ ownerLabel,
7880
+ elementId,
7881
+ field: `indicator.${stateName}.imageId`,
7882
+ targetId: visual.imageId,
7883
+ });
7884
+ if (!result.valid) {
7885
+ return result;
7886
+ }
7887
+ }
7888
+ }
7889
+
7545
7890
  for (const field of ["hoverSoundId", "clickSoundId"]) {
7546
7891
  if (element[field] !== undefined) {
7547
7892
  const result = assertSoundReference({
@@ -7639,6 +7984,23 @@ export const assertInvariants = ({ state }) => {
7639
7984
  }
7640
7985
  }
7641
7986
 
7987
+ for (const {
7988
+ index,
7989
+ resourceId,
7990
+ } of getLayoutTextContentReferenceEntries(element.content)) {
7991
+ if (!isVariableReferenceTarget(state, resourceId)) {
7992
+ return invalidInvariant(
7993
+ `${ownerLabel} element content.${index}.reference.resourceId must reference an existing non-folder variable`,
7994
+ {
7995
+ [ownerIdField]: ownerId,
7996
+ elementId,
7997
+ field: `content.${index}.reference.resourceId`,
7998
+ targetId: resourceId,
7999
+ },
8000
+ );
8001
+ }
8002
+ }
8003
+
7642
8004
  if (element.variableId !== undefined) {
7643
8005
  const result = assertVariableReference({
7644
8006
  ownerIdField,
@@ -11383,6 +11745,36 @@ const validateVisualElementReferenceTargets = ({
11383
11745
  );
11384
11746
  }
11385
11747
 
11748
+ if (
11749
+ data.indicator !== undefined &&
11750
+ !LAYOUT_TEXT_REVEAL_INDICATOR_ELEMENT_TYPES.includes(data.type)
11751
+ ) {
11752
+ return invalidFromErrorFactory(
11753
+ errorFactory,
11754
+ `${ownerLabel} element indicator can only be provided for text revealing elements`,
11755
+ {
11756
+ [ownerIdField]: ownerId,
11757
+ elementId,
11758
+ field: "indicator",
11759
+ },
11760
+ );
11761
+ }
11762
+
11763
+ if (
11764
+ data.content !== undefined &&
11765
+ !LAYOUT_TEXT_CONTENT_ELEMENT_TYPES.includes(data.type)
11766
+ ) {
11767
+ return invalidFromErrorFactory(
11768
+ errorFactory,
11769
+ `${ownerLabel} element content can only be provided for text elements`,
11770
+ {
11771
+ [ownerIdField]: ownerId,
11772
+ elementId,
11773
+ field: "content",
11774
+ },
11775
+ );
11776
+ }
11777
+
11386
11778
  if (
11387
11779
  data.type === "spritesheet-animation" ||
11388
11780
  data.resourceId !== undefined ||
@@ -11483,6 +11875,66 @@ const validateVisualElementReferenceTargets = ({
11483
11875
  }
11484
11876
  }
11485
11877
 
11878
+ for (const stateName of ["revealing", "complete"]) {
11879
+ const visual = data.indicator?.[stateName];
11880
+ if (
11881
+ visual?.kind === "spritesheet" ||
11882
+ visual?.resourceId !== undefined ||
11883
+ visual?.animationName !== undefined
11884
+ ) {
11885
+ const spritesheet = state.spritesheets?.items?.[visual.resourceId];
11886
+ if (!isPlainObject(spritesheet) || spritesheet.type === "folder") {
11887
+ return invalidFromErrorFactory(
11888
+ errorFactory,
11889
+ `${ownerLabel} element indicator.${stateName}.resourceId must reference an existing non-folder spritesheet`,
11890
+ {
11891
+ [ownerIdField]: ownerId,
11892
+ elementId,
11893
+ field: `indicator.${stateName}.resourceId`,
11894
+ targetId: visual.resourceId,
11895
+ },
11896
+ );
11897
+ }
11898
+
11899
+ if (
11900
+ !isNonEmptyString(visual.animationName) ||
11901
+ !isPlainObject(spritesheet.animations?.[visual.animationName])
11902
+ ) {
11903
+ return invalidFromErrorFactory(
11904
+ errorFactory,
11905
+ `${ownerLabel} element indicator.${stateName}.animationName must reference an existing spritesheet animation`,
11906
+ {
11907
+ [ownerIdField]: ownerId,
11908
+ elementId,
11909
+ field: `indicator.${stateName}.animationName`,
11910
+ targetId: visual.animationName,
11911
+ },
11912
+ );
11913
+ }
11914
+
11915
+ continue;
11916
+ }
11917
+
11918
+ const imageId = visual?.imageId;
11919
+ if (imageId === undefined) {
11920
+ continue;
11921
+ }
11922
+
11923
+ const image = state.images.items[imageId];
11924
+ if (!isPlainObject(image) || image.type === "folder") {
11925
+ return invalidFromErrorFactory(
11926
+ errorFactory,
11927
+ `${ownerLabel} element indicator.${stateName}.imageId must reference an existing non-folder image`,
11928
+ {
11929
+ [ownerIdField]: ownerId,
11930
+ elementId,
11931
+ field: `indicator.${stateName}.imageId`,
11932
+ targetId: imageId,
11933
+ },
11934
+ );
11935
+ }
11936
+ }
11937
+
11486
11938
  if (data.hoverSoundId !== undefined) {
11487
11939
  const sound = state.sounds.items[data.hoverSoundId];
11488
11940
  if (!isPlainObject(sound) || sound.type === "folder") {
@@ -11710,6 +12162,23 @@ const validateVisualElementReferenceTargets = ({
11710
12162
  }
11711
12163
  }
11712
12164
 
12165
+ for (const { index, resourceId } of getLayoutTextContentReferenceEntries(
12166
+ data.content,
12167
+ )) {
12168
+ if (!isVariableReferenceTarget(state, resourceId)) {
12169
+ return invalidFromErrorFactory(
12170
+ errorFactory,
12171
+ `${ownerLabel} element content.${index}.reference.resourceId must reference an existing non-folder variable`,
12172
+ {
12173
+ [ownerIdField]: ownerId,
12174
+ elementId,
12175
+ field: `content.${index}.reference.resourceId`,
12176
+ targetId: resourceId,
12177
+ },
12178
+ );
12179
+ }
12180
+ }
12181
+
11713
12182
  if (data.variableId !== undefined) {
11714
12183
  if (!isVariableReferenceTarget(state, data.variableId)) {
11715
12184
  return invalidFromErrorFactory(
@@ -17736,6 +18205,16 @@ const COMMAND_DEFINITIONS = [
17736
18205
  "payload.parentId must reference a folder sprite item",
17737
18206
  );
17738
18207
  }
18208
+
18209
+ const parentNode = findTreeNode({
18210
+ nodes: collection.tree,
18211
+ nodeId: parentId,
18212
+ });
18213
+ if (!parentNode) {
18214
+ return invalidPrecondition(
18215
+ "payload.parentId must reference a folder sprite item in the tree",
18216
+ );
18217
+ }
17739
18218
  }
17740
18219
 
17741
18220
  if (payload.positionTargetId !== undefined) {
@@ -17745,6 +18224,16 @@ const COMMAND_DEFINITIONS = [
17745
18224
  );
17746
18225
  }
17747
18226
 
18227
+ const targetNode = findTreeNode({
18228
+ nodes: collection.tree,
18229
+ nodeId: payload.positionTargetId,
18230
+ });
18231
+ if (!targetNode) {
18232
+ return invalidPrecondition(
18233
+ "payload.positionTargetId must reference an existing sprite item in the tree",
18234
+ );
18235
+ }
18236
+
17748
18237
  const targetParentId = getNodeParentId({
17749
18238
  tree: collection.tree,
17750
18239
  nodeId: payload.positionTargetId,
@@ -18076,6 +18565,11 @@ const COMMAND_DEFINITIONS = [
18076
18565
  nodes: collection.tree,
18077
18566
  nodeId: payload.spriteId,
18078
18567
  });
18568
+ if (!currentNode) {
18569
+ return invalidPrecondition(
18570
+ "payload.spriteId must reference an existing sprite item in the tree",
18571
+ );
18572
+ }
18079
18573
 
18080
18574
  if (payload.parentId !== undefined && payload.parentId !== null) {
18081
18575
  const parentItem = collection.items[payload.parentId];
@@ -18085,6 +18579,16 @@ const COMMAND_DEFINITIONS = [
18085
18579
  );
18086
18580
  }
18087
18581
 
18582
+ const parentNode = findTreeNode({
18583
+ nodes: collection.tree,
18584
+ nodeId: payload.parentId,
18585
+ });
18586
+ if (!parentNode) {
18587
+ return invalidPrecondition(
18588
+ "payload.parentId must reference a folder sprite item in the tree",
18589
+ );
18590
+ }
18591
+
18088
18592
  const descendantIds = new Set(
18089
18593
  collectTreeDescendantIds({
18090
18594
  node: currentNode,
@@ -18111,6 +18615,16 @@ const COMMAND_DEFINITIONS = [
18111
18615
  );
18112
18616
  }
18113
18617
 
18618
+ const targetNode = findTreeNode({
18619
+ nodes: collection.tree,
18620
+ nodeId: payload.positionTargetId,
18621
+ });
18622
+ if (!targetNode) {
18623
+ return invalidPrecondition(
18624
+ "payload.positionTargetId must reference an existing sprite item in the tree",
18625
+ );
18626
+ }
18627
+
18114
18628
  const targetParentId = getNodeParentId({
18115
18629
  tree: collection.tree,
18116
18630
  nodeId: payload.positionTargetId,