@routevn/creator-model 1.5.2 → 1.6.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/model.js +147 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routevn/creator-model",
3
- "version": "1.5.2",
3
+ "version": "1.6.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/model.js CHANGED
@@ -343,6 +343,7 @@ const LAYOUT_TYPE_KEYS = [
343
343
  ];
344
344
  const LAYOUT_ELEMENT_TEXT_STYLE_ALIGN_KEYS = ["left", "center", "right"];
345
345
  const LAYOUT_TEXT_REVEAL_EFFECT_KEYS = ["typewriter", "softWipe", "none"];
346
+ const LAYOUT_ELEMENT_BLUR_KERNEL_SIZE_OPTIONS = [5, 7, 9, 11, 13, 15];
346
347
  const CONTROL_KEYBOARD_KEYS = [
347
348
  "enter",
348
349
  "space",
@@ -381,7 +382,7 @@ const LAYOUT_ELEMENT_BASE_TYPES = [
381
382
  "container-ref-confirm-dialog-ok",
382
383
  "container-ref-confirm-dialog-cancel",
383
384
  ];
384
- export const SCHEMA_VERSION = 5;
385
+ export const SCHEMA_VERSION = 6;
385
386
  const LAYOUT_CONTAINER_ELEMENT_TYPES = [
386
387
  "folder",
387
388
  "container",
@@ -3348,6 +3349,56 @@ const validateLayoutElementInteraction = ({
3348
3349
  }
3349
3350
  };
3350
3351
 
3352
+ const validateLayoutElementBlur = ({ blur, path, errorFactory }) => {
3353
+ if (!isPlainObject(blur)) {
3354
+ return invalidFromErrorFactory(
3355
+ errorFactory,
3356
+ `${path} must be an object when provided`,
3357
+ );
3358
+ }
3359
+
3360
+ {
3361
+ const result = validateAllowedKeys({
3362
+ value: blur,
3363
+ allowedKeys: ["x", "y", "quality", "kernelSize", "repeatEdgePixels"],
3364
+ path,
3365
+ errorFactory,
3366
+ });
3367
+ if (result?.valid === false) {
3368
+ return result;
3369
+ }
3370
+ }
3371
+
3372
+ for (const key of ["x", "y", "quality"]) {
3373
+ if (blur[key] !== undefined && !isFiniteNumber(blur[key])) {
3374
+ return invalidFromErrorFactory(
3375
+ errorFactory,
3376
+ `${path}.${key} must be a finite number when provided`,
3377
+ );
3378
+ }
3379
+ }
3380
+
3381
+ if (
3382
+ blur.kernelSize !== undefined &&
3383
+ !LAYOUT_ELEMENT_BLUR_KERNEL_SIZE_OPTIONS.includes(blur.kernelSize)
3384
+ ) {
3385
+ return invalidFromErrorFactory(
3386
+ errorFactory,
3387
+ `${path}.kernelSize must be one of ${LAYOUT_ELEMENT_BLUR_KERNEL_SIZE_OPTIONS.join(", ")} when provided`,
3388
+ );
3389
+ }
3390
+
3391
+ if (
3392
+ blur.repeatEdgePixels !== undefined &&
3393
+ typeof blur.repeatEdgePixels !== "boolean"
3394
+ ) {
3395
+ return invalidFromErrorFactory(
3396
+ errorFactory,
3397
+ `${path}.repeatEdgePixels must be a boolean when provided`,
3398
+ );
3399
+ }
3400
+ };
3401
+
3351
3402
  const validateLayoutElementData = ({
3352
3403
  data,
3353
3404
  path,
@@ -3372,6 +3423,7 @@ const validateLayoutElementData = ({
3372
3423
  "scaleY",
3373
3424
  "rotation",
3374
3425
  "opacity",
3426
+ "blur",
3375
3427
  "fill",
3376
3428
  "border",
3377
3429
  "text",
@@ -3506,6 +3558,26 @@ const validateLayoutElementData = ({
3506
3558
  );
3507
3559
  }
3508
3560
 
3561
+ if (data.blur !== undefined) {
3562
+ {
3563
+ const result = validateLayoutElementBlur({
3564
+ blur: data.blur,
3565
+ path: `${path}.blur`,
3566
+ errorFactory,
3567
+ });
3568
+ if (result?.valid === false) {
3569
+ return result;
3570
+ }
3571
+ }
3572
+
3573
+ if (data.type !== undefined && data.type !== "sprite") {
3574
+ return invalidFromErrorFactory(
3575
+ errorFactory,
3576
+ `${path}.blur can only be provided for sprite elements`,
3577
+ );
3578
+ }
3579
+ }
3580
+
3509
3581
  for (const key of [
3510
3582
  "text",
3511
3583
  "resourceId",
@@ -3947,6 +4019,7 @@ const validateLayoutElementItems = ({ items, path, errorFactory }) => {
3947
4019
  "scaleY",
3948
4020
  "rotation",
3949
4021
  "opacity",
4022
+ "blur",
3950
4023
  "fill",
3951
4024
  "border",
3952
4025
  "text",
@@ -11090,6 +11163,18 @@ const validateVisualElementReferenceTargets = ({
11090
11163
  state,
11091
11164
  errorFactory,
11092
11165
  }) => {
11166
+ if (data.blur !== undefined && data.type !== "sprite") {
11167
+ return invalidFromErrorFactory(
11168
+ errorFactory,
11169
+ `${ownerLabel} element blur can only be provided for sprite elements`,
11170
+ {
11171
+ [ownerIdField]: ownerId,
11172
+ elementId,
11173
+ field: "blur",
11174
+ },
11175
+ );
11176
+ }
11177
+
11093
11178
  if (
11094
11179
  data.type === "spritesheet-animation" ||
11095
11180
  data.resourceId !== undefined ||
@@ -13181,6 +13266,7 @@ const COMMAND_DEFINITIONS = [
13181
13266
  value: payload,
13182
13267
  allowedKeys: [
13183
13268
  "sectionId",
13269
+ "sceneId",
13184
13270
  "parentId",
13185
13271
  "index",
13186
13272
  "position",
@@ -13198,6 +13284,12 @@ const COMMAND_DEFINITIONS = [
13198
13284
  return invalidPayload("payload.sectionId must be a non-empty string");
13199
13285
  }
13200
13286
 
13287
+ if (payload.sceneId !== undefined && !isNonEmptyString(payload.sceneId)) {
13288
+ return invalidPayload(
13289
+ "payload.sceneId must be a non-empty string when provided",
13290
+ );
13291
+ }
13292
+
13201
13293
  if (
13202
13294
  payload.parentId !== undefined &&
13203
13295
  payload.parentId !== null &&
@@ -13229,10 +13321,42 @@ const COMMAND_DEFINITIONS = [
13229
13321
  );
13230
13322
  }
13231
13323
 
13324
+ const targetSceneId = payload.sceneId ?? location.sceneId;
13325
+ const targetScene = state.scenes.items[targetSceneId];
13326
+ if (!isPlainObject(targetScene)) {
13327
+ return invalidPrecondition(
13328
+ "payload.sceneId must reference an existing scene",
13329
+ );
13330
+ }
13331
+
13332
+ if (targetScene.type !== "scene") {
13333
+ return invalidPrecondition(
13334
+ "payload.sceneId must reference a non-folder scene",
13335
+ );
13336
+ }
13337
+
13338
+ const targetSections =
13339
+ targetScene.sections ?? createEmptyNestedCollection();
13232
13340
  const sectionNode = findTreeNode({
13233
13341
  nodes: location.sections.tree,
13234
13342
  nodeId: payload.sectionId,
13235
13343
  });
13344
+ const isCrossSceneMove = targetSceneId !== location.sceneId;
13345
+
13346
+ if (isCrossSceneMove) {
13347
+ const sourceSectionCount = Object.keys(
13348
+ location.sections?.items ?? {},
13349
+ ).length;
13350
+ const movedSectionCount = collectTreeDescendantIds({
13351
+ node: sectionNode,
13352
+ }).length;
13353
+
13354
+ if (sourceSectionCount <= movedSectionCount) {
13355
+ return invalidPrecondition(
13356
+ "payload.sectionId must not move the last section out of a scene",
13357
+ );
13358
+ }
13359
+ }
13236
13360
 
13237
13361
  if (payload.parentId !== undefined && payload.parentId !== null) {
13238
13362
  const parentLocation = findSectionLocation({
@@ -13245,9 +13369,9 @@ const COMMAND_DEFINITIONS = [
13245
13369
  );
13246
13370
  }
13247
13371
 
13248
- if (parentLocation.sceneId !== location.sceneId) {
13372
+ if (parentLocation.sceneId !== targetSceneId) {
13249
13373
  return invalidPrecondition(
13250
- "payload.parentId must reference a section in the same scene",
13374
+ "payload.parentId must reference a section in the target scene",
13251
13375
  );
13252
13376
  }
13253
13377
 
@@ -13281,14 +13405,14 @@ const COMMAND_DEFINITIONS = [
13281
13405
  );
13282
13406
  }
13283
13407
 
13284
- if (targetLocation.sceneId !== location.sceneId) {
13408
+ if (targetLocation.sceneId !== targetSceneId) {
13285
13409
  return invalidPrecondition(
13286
- "payload.positionTargetId must reference a section in the same scene",
13410
+ "payload.positionTargetId must reference a section in the target scene",
13287
13411
  );
13288
13412
  }
13289
13413
 
13290
13414
  const targetParentId = getNodeParentId({
13291
- tree: location.sections.tree,
13415
+ tree: targetSections.tree,
13292
13416
  nodeId: payload.positionTargetId,
13293
13417
  });
13294
13418
 
@@ -13304,6 +13428,10 @@ const COMMAND_DEFINITIONS = [
13304
13428
  state,
13305
13429
  sectionId: payload.sectionId,
13306
13430
  });
13431
+ const targetSceneId = payload.sceneId ?? location.sceneId;
13432
+ const targetScene = state.scenes.items[targetSceneId];
13433
+ targetScene.sections ??= createEmptyNestedCollection();
13434
+ const targetSections = targetScene.sections;
13307
13435
  const sectionNodeResult = removeNodeOrResult({
13308
13436
  tree: location.sections.tree,
13309
13437
  nodeId: payload.sectionId,
@@ -13313,8 +13441,20 @@ const COMMAND_DEFINITIONS = [
13313
13441
  return sectionNodeResult;
13314
13442
  }
13315
13443
 
13444
+ if (targetSections !== location.sections) {
13445
+ const movedSectionIds = collectTreeDescendantIds({
13446
+ node: sectionNodeResult.node,
13447
+ });
13448
+
13449
+ for (const movedSectionId of movedSectionIds) {
13450
+ targetSections.items[movedSectionId] =
13451
+ location.sections.items[movedSectionId];
13452
+ delete location.sections.items[movedSectionId];
13453
+ }
13454
+ }
13455
+
13316
13456
  insertTreeNode({
13317
- tree: location.sections.tree,
13457
+ tree: targetSections.tree,
13318
13458
  node: sectionNodeResult.node,
13319
13459
  parentId: payload.parentId ?? null,
13320
13460
  index: payload.index,