slice-machine-ui 2.16.2-alpha.jp-cr-ui-multiple-improvements-rendering-logic.1 → 2.16.2-alpha.jp-cr-ui-multiple-improvements-rendering-logic.3

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.
@@ -7,14 +7,15 @@ import {
7
7
  TreeViewSection,
8
8
  } from "@prismicio/editor-ui";
9
9
  import {
10
+ CustomType,
11
+ Group,
10
12
  Link,
11
13
  LinkConfig,
12
- UID,
14
+ NestableWidget,
13
15
  } from "@prismicio/types-internal/lib/customtypes";
14
16
  import { useSelector } from "react-redux";
15
17
 
16
- import { CustomTypeSM, TabFields } from "@/legacy/lib/models/common/CustomType";
17
- import { GroupSM } from "@/legacy/lib/models/common/Group";
18
+ import { CustomTypes } from "@/legacy/lib/models/common/CustomType";
18
19
  import { selectAllCustomTypes } from "@/modules/availableCustomTypes";
19
20
  import { isValidObject } from "@/utils/isValidObject";
20
21
 
@@ -270,10 +271,10 @@ export function ContentRelationshipFieldPicker(
270
271
  }
271
272
 
272
273
  interface TreeViewCustomTypeProps {
273
- customType: CustomTypeSM;
274
+ customType: CustomType;
274
275
  fieldCheckMap: PickerCustomType;
275
276
  onChange: (newValue: PickerCustomType) => void;
276
- customTypes: CustomTypeSM[];
277
+ customTypes: CustomType[];
277
278
  }
278
279
 
279
280
  function TreeViewCustomType(props: TreeViewCustomTypeProps) {
@@ -293,116 +294,115 @@ function TreeViewCustomType(props: TreeViewCustomTypeProps) {
293
294
  )}
294
295
  badge={customType.format === "page" ? "Page type" : "Custom type"}
295
296
  >
296
- {customType.tabs
297
- .flatMap((tab) => tab.value)
298
- .map((field) => {
299
- if (isUidField(field)) return null;
300
-
301
- // Group field
297
+ {mapCustomTypeStaticFields(customType, ({ fieldId, field }) => {
298
+ // Group field
302
299
 
303
- if (isGroupField(field)) {
304
- const onGroupFieldChange = (
305
- newGroupFields: PickerFirstLevelGroupFieldValue,
306
- ) => {
307
- onCustomTypeChange({
308
- ...customTypeFieldsCheckMap,
309
- [field.key]: { type: "group", value: newGroupFields },
310
- });
311
- };
312
-
313
- const groupFieldCheckMap =
314
- customTypeFieldsCheckMap[field.key] ?? {};
315
-
316
- return (
317
- <TreeViewFirstLevelGroupField
318
- key={field.key}
319
- group={field}
320
- onChange={onGroupFieldChange}
321
- fieldCheckMap={
322
- groupFieldCheckMap.type === "group"
323
- ? groupFieldCheckMap.value
324
- : {}
325
- }
326
- customTypes={customTypes}
327
- />
328
- );
329
- }
300
+ if (isGroupField(field)) {
301
+ const onGroupFieldChange = (
302
+ newGroupFields: PickerFirstLevelGroupFieldValue,
303
+ ) => {
304
+ onCustomTypeChange({
305
+ ...customTypeFieldsCheckMap,
306
+ [fieldId]: { type: "group", value: newGroupFields },
307
+ });
308
+ };
330
309
 
331
- // Content relationship field
310
+ const groupFieldCheckMap = customTypeFieldsCheckMap[fieldId] ?? {};
332
311
 
333
- if (isContentRelationshipField(field)) {
334
- const onContentRelationshipFieldChange = (
335
- newCrFields: PickerContentRelationshipFieldValue,
336
- ) => {
337
- onCustomTypeChange({
338
- ...customTypeFieldsCheckMap,
339
- [field.key]: {
340
- type: "contentRelationship",
341
- value: newCrFields,
342
- },
343
- });
344
- };
345
-
346
- const crFieldCheckMap = customTypeFieldsCheckMap[field.key] ?? {};
347
-
348
- return (
349
- <TreeViewContentRelationshipField
350
- key={field.key}
351
- field={field}
352
- onChange={onContentRelationshipFieldChange}
353
- fieldCheckMap={
354
- crFieldCheckMap.type === "contentRelationship"
355
- ? crFieldCheckMap.value
356
- : {}
357
- }
358
- customTypes={customTypes}
359
- />
360
- );
361
- }
312
+ return (
313
+ <TreeViewFirstLevelGroupField
314
+ key={fieldId}
315
+ group={field}
316
+ groupId={fieldId}
317
+ onChange={onGroupFieldChange}
318
+ fieldCheckMap={
319
+ groupFieldCheckMap.type === "group"
320
+ ? groupFieldCheckMap.value
321
+ : {}
322
+ }
323
+ customTypes={customTypes}
324
+ />
325
+ );
326
+ }
362
327
 
363
- // Regular field
328
+ // Content relationship field
364
329
 
365
- const onCheckedChange = (newValue: boolean) => {
330
+ if (isContentRelationshipField(field)) {
331
+ const onContentRelationshipFieldChange = (
332
+ newCrFields: PickerContentRelationshipFieldValue,
333
+ ) => {
366
334
  onCustomTypeChange({
367
335
  ...customTypeFieldsCheckMap,
368
- [field.key]: { type: "checkbox", value: newValue },
336
+ [fieldId]: {
337
+ type: "contentRelationship",
338
+ value: newCrFields,
339
+ },
369
340
  });
370
341
  };
371
342
 
343
+ const crFieldCheckMap = customTypeFieldsCheckMap[fieldId] ?? {};
344
+
372
345
  return (
373
- <TreeViewCheckbox
374
- key={field.key}
375
- title={field.key}
376
- checked={customTypeFieldsCheckMap[field.key]?.value === true}
377
- onCheckedChange={onCheckedChange}
346
+ <TreeViewContentRelationshipField
347
+ key={fieldId}
348
+ field={field}
349
+ fieldId={fieldId}
350
+ onChange={onContentRelationshipFieldChange}
351
+ fieldCheckMap={
352
+ crFieldCheckMap.type === "contentRelationship"
353
+ ? crFieldCheckMap.value
354
+ : {}
355
+ }
356
+ customTypes={customTypes}
378
357
  />
379
358
  );
380
- })}
359
+ }
360
+
361
+ // Regular field
362
+
363
+ const onCheckedChange = (newValue: boolean) => {
364
+ onCustomTypeChange({
365
+ ...customTypeFieldsCheckMap,
366
+ [fieldId]: { type: "checkbox", value: newValue },
367
+ });
368
+ };
369
+
370
+ return (
371
+ <TreeViewCheckbox
372
+ key={fieldId}
373
+ title={fieldId}
374
+ checked={customTypeFieldsCheckMap[fieldId]?.value === true}
375
+ onCheckedChange={onCheckedChange}
376
+ />
377
+ );
378
+ })}
381
379
  </TreeViewSection>
382
380
  );
383
381
  }
384
382
 
385
383
  interface TreeViewContentRelationshipFieldProps {
386
- field: { key: string; value: Link };
384
+ fieldId: string;
385
+ field: Link;
387
386
  fieldCheckMap: PickerContentRelationshipFieldValue;
388
387
  onChange: (newValue: PickerContentRelationshipFieldValue) => void;
389
- customTypes: CustomTypeSM[];
388
+ customTypes: CustomType[];
390
389
  }
391
390
 
392
391
  function TreeViewContentRelationshipField(
393
392
  props: TreeViewContentRelationshipFieldProps,
394
393
  ) {
395
394
  const {
396
- field: crField,
395
+ field,
396
+ fieldId,
397
397
  fieldCheckMap: crFieldsCheckMap,
398
398
  onChange: onCrFieldChange,
399
399
  customTypes,
400
400
  } = props;
401
401
 
402
- if (!crField.value.config?.customtypes) return null;
402
+ if (!field.config?.customtypes) return null;
403
403
 
404
404
  const resolvedCustomTypes = resolveContentRelationshipCustomTypes(
405
- crField.value.config.customtypes,
405
+ field.config.customtypes,
406
406
  customTypes,
407
407
  );
408
408
 
@@ -410,7 +410,7 @@ function TreeViewContentRelationshipField(
410
410
 
411
411
  return (
412
412
  <TreeViewSection
413
- title={crField.key}
413
+ title={fieldId}
414
414
  subtitle={getExposedFieldsLabel(countPickedFields(crFieldsCheckMap))}
415
415
  >
416
416
  {resolvedCustomTypes.map((customType) => {
@@ -436,58 +436,55 @@ function TreeViewContentRelationshipField(
436
436
  )}
437
437
  badge={customType.format === "page" ? "Page type" : "Custom type"}
438
438
  >
439
- {customType.tabs
440
- .flatMap((tab) => tab.value)
441
- .map((field) => {
442
- if (isUidField(field)) return null;
443
-
444
- // Group field
445
-
446
- if (isGroupField(field)) {
447
- const onGroupFieldsChange = (
448
- newGroupFields: PickerLeafGroupFieldValue,
449
- ) => {
450
- onNestedCustomTypeChange({
451
- ...nestedCtFieldsCheckMap,
452
- [field.key]: { type: "group", value: newGroupFields },
453
- });
454
- };
455
-
456
- const groupFieldCheckMap =
457
- nestedCtFieldsCheckMap[field.key] ?? {};
458
-
459
- return (
460
- <TreeViewLeafGroupField
461
- key={field.key}
462
- group={field}
463
- onChange={onGroupFieldsChange}
464
- fieldCheckMap={
465
- groupFieldCheckMap.type === "group"
466
- ? groupFieldCheckMap.value
467
- : {}
468
- }
469
- />
470
- );
471
- }
472
-
473
- // Regular field
474
-
475
- const onCheckedChange = (newChecked: boolean) => {
439
+ {mapCustomTypeStaticFields(customType, ({ fieldId, field }) => {
440
+ // Group field
441
+
442
+ if (isGroupField(field)) {
443
+ const onGroupFieldsChange = (
444
+ newGroupFields: PickerLeafGroupFieldValue,
445
+ ) => {
476
446
  onNestedCustomTypeChange({
477
447
  ...nestedCtFieldsCheckMap,
478
- [field.key]: { type: "checkbox", value: newChecked },
448
+ [fieldId]: { type: "group", value: newGroupFields },
479
449
  });
480
450
  };
481
451
 
452
+ const groupFieldCheckMap =
453
+ nestedCtFieldsCheckMap[fieldId] ?? {};
454
+
482
455
  return (
483
- <TreeViewCheckbox
484
- key={field.key}
485
- title={field.key}
486
- checked={nestedCtFieldsCheckMap[field.key]?.value === true}
487
- onCheckedChange={onCheckedChange}
456
+ <TreeViewLeafGroupField
457
+ key={fieldId}
458
+ group={field}
459
+ groupId={fieldId}
460
+ onChange={onGroupFieldsChange}
461
+ fieldCheckMap={
462
+ groupFieldCheckMap.type === "group"
463
+ ? groupFieldCheckMap.value
464
+ : {}
465
+ }
488
466
  />
489
467
  );
490
- })}
468
+ }
469
+
470
+ // Regular field
471
+
472
+ const onCheckedChange = (newChecked: boolean) => {
473
+ onNestedCustomTypeChange({
474
+ ...nestedCtFieldsCheckMap,
475
+ [fieldId]: { type: "checkbox", value: newChecked },
476
+ });
477
+ };
478
+
479
+ return (
480
+ <TreeViewCheckbox
481
+ key={fieldId}
482
+ title={fieldId}
483
+ checked={nestedCtFieldsCheckMap[fieldId]?.value === true}
484
+ onCheckedChange={onCheckedChange}
485
+ />
486
+ );
487
+ })}
491
488
  </TreeViewSection>
492
489
  );
493
490
  })}
@@ -496,7 +493,8 @@ function TreeViewContentRelationshipField(
496
493
  }
497
494
 
498
495
  interface TreeViewLeafGroupFieldProps {
499
- group: { key: string; value: GroupSM };
496
+ group: Group;
497
+ groupId: string;
500
498
  fieldCheckMap: PickerLeafGroupFieldValue;
501
499
  onChange: (newValue: PickerLeafGroupFieldValue) => void;
502
500
  }
@@ -504,32 +502,33 @@ interface TreeViewLeafGroupFieldProps {
504
502
  function TreeViewLeafGroupField(props: TreeViewLeafGroupFieldProps) {
505
503
  const {
506
504
  group,
505
+ groupId,
507
506
  fieldCheckMap: groupFieldsCheckMap,
508
507
  onChange: onGroupFieldChange,
509
508
  } = props;
510
509
 
511
- if (!group.value.config?.fields) return null;
510
+ if (!group.config?.fields) return null;
512
511
 
513
512
  return (
514
513
  <TreeViewSection
515
- key={group.key}
516
- title={group.key}
514
+ key={groupId}
515
+ title={groupId}
517
516
  subtitle={getExposedFieldsLabel(countPickedFields(groupFieldsCheckMap))}
518
517
  badge="Group"
519
518
  >
520
- {group.value.config?.fields.map((field) => {
519
+ {mapGroupFields(group, ({ fieldId }) => {
521
520
  const onCheckedChange = (newChecked: boolean) => {
522
521
  onGroupFieldChange({
523
522
  ...groupFieldsCheckMap,
524
- [field.key]: { type: "checkbox", value: newChecked },
523
+ [fieldId]: { type: "checkbox", value: newChecked },
525
524
  });
526
525
  };
527
526
 
528
527
  return (
529
528
  <TreeViewCheckbox
530
- key={field.key}
531
- title={field.key}
532
- checked={groupFieldsCheckMap[field.key]?.value === true}
529
+ key={fieldId}
530
+ title={fieldId}
531
+ checked={groupFieldsCheckMap[fieldId]?.value === true}
533
532
  onCheckedChange={onCheckedChange}
534
533
  />
535
534
  );
@@ -539,10 +538,11 @@ function TreeViewLeafGroupField(props: TreeViewLeafGroupFieldProps) {
539
538
  }
540
539
 
541
540
  interface TreeViewFirstLevelGroupFieldProps {
542
- group: { key: string; value: GroupSM };
541
+ group: Group;
542
+ groupId: string;
543
543
  fieldCheckMap: PickerFirstLevelGroupFieldValue;
544
544
  onChange: (newValue: PickerFirstLevelGroupFieldValue) => void;
545
- customTypes: CustomTypeSM[];
545
+ customTypes: CustomType[];
546
546
  }
547
547
 
548
548
  function TreeViewFirstLevelGroupField(
@@ -550,35 +550,37 @@ function TreeViewFirstLevelGroupField(
550
550
  ) {
551
551
  const {
552
552
  group,
553
+ groupId,
553
554
  fieldCheckMap: groupFieldsCheckMap,
554
555
  onChange: onGroupFieldChange,
555
556
  customTypes,
556
557
  } = props;
557
558
 
558
- if (!group.value.config?.fields) return null;
559
+ if (!group.config?.fields) return null;
559
560
 
560
561
  return (
561
- <TreeViewSection key={group.key} title={group.key} badge="Group">
562
- {group.value.config.fields.map((field) => {
562
+ <TreeViewSection key={groupId} title={groupId} badge="Group">
563
+ {mapGroupFields(group, ({ fieldId, field }) => {
563
564
  if (isContentRelationshipField(field)) {
564
565
  const onContentRelationshipFieldChange = (
565
566
  newCrFields: PickerContentRelationshipFieldValue,
566
567
  ) => {
567
568
  onGroupFieldChange({
568
569
  ...groupFieldsCheckMap,
569
- [field.key]: {
570
+ [fieldId]: {
570
571
  type: "contentRelationship",
571
572
  value: newCrFields,
572
573
  },
573
574
  });
574
575
  };
575
576
 
576
- const crFieldCheckMap = groupFieldsCheckMap[field.key] ?? {};
577
+ const crFieldCheckMap = groupFieldsCheckMap[fieldId] ?? {};
577
578
 
578
579
  return (
579
580
  <TreeViewContentRelationshipField
580
- key={field.key}
581
+ key={fieldId}
581
582
  field={field}
583
+ fieldId={fieldId}
582
584
  fieldCheckMap={
583
585
  crFieldCheckMap.type === "contentRelationship"
584
586
  ? crFieldCheckMap.value
@@ -593,15 +595,15 @@ function TreeViewFirstLevelGroupField(
593
595
  const onCheckedChange = (newChecked: boolean) => {
594
596
  onGroupFieldChange({
595
597
  ...groupFieldsCheckMap,
596
- [field.key]: { type: "checkbox", value: newChecked },
598
+ [fieldId]: { type: "checkbox", value: newChecked },
597
599
  });
598
600
  };
599
601
 
600
602
  return (
601
603
  <TreeViewCheckbox
602
- key={field.key}
603
- title={field.key}
604
- checked={groupFieldsCheckMap[field.key]?.value === true}
604
+ key={fieldId}
605
+ title={fieldId}
606
+ checked={groupFieldsCheckMap[fieldId]?.value === true}
605
607
  onCheckedChange={onCheckedChange}
606
608
  />
607
609
  );
@@ -619,14 +621,14 @@ function getExposedFieldsLabel(count: number) {
619
621
  * Gets all the existing local custom types from the store, filters and sorts
620
622
  * them.
621
623
  */
622
- function useCustomTypes(): CustomTypeSM[] {
624
+ function useCustomTypes(): CustomType[] {
623
625
  const allCustomTypes = useSelector(selectAllCustomTypes);
624
- const localCustomTypes = allCustomTypes.flatMap<CustomTypeSM>((ct) => {
626
+ const localCustomTypes = allCustomTypes.flatMap<CustomType>((ct) => {
625
627
  // In the store we have remote and local custom types, we want to show
626
628
  // the local ones, so that the user is able to create a content
627
629
  // relationship with custom types present on the user's computer (pushed
628
630
  // or not).
629
- return "local" in ct ? ct.local : [];
631
+ return "local" in ct ? CustomTypes.fromSM(ct.local) : [];
630
632
  });
631
633
 
632
634
  localCustomTypes.sort((a, b) => a.id.localeCompare(b.id));
@@ -636,9 +638,9 @@ function useCustomTypes(): CustomTypeSM[] {
636
638
 
637
639
  function resolveContentRelationshipCustomTypes(
638
640
  customTypes: LinkCustomtypes,
639
- localCustomTypes: CustomTypeSM[],
640
- ): CustomTypeSM[] {
641
- const fields = customTypes.flatMap<CustomTypeSM>((customType) => {
641
+ localCustomTypes: CustomType[],
642
+ ): CustomType[] {
643
+ const fields = customTypes.flatMap<CustomType>((customType) => {
642
644
  if (typeof customType === "string") return [];
643
645
  return localCustomTypes.find((ct) => ct.id === customType.id) ?? [];
644
646
  });
@@ -846,29 +848,54 @@ function isCheckboxValue(value: unknown): value is PickerCheckboxField {
846
848
  return "type" in value && value.type === "checkbox";
847
849
  }
848
850
 
849
- function isGroupField(
850
- field: TabFields[number],
851
- ): field is { key: string; value: GroupSM } {
852
- return field.value.type === "Group";
851
+ function isGroupField(field: NestableWidget | Group): field is Group {
852
+ return field.type === "Group";
853
853
  }
854
854
 
855
855
  function isContentRelationshipField(
856
- field: TabFields[number],
857
- ): field is { key: string; value: Link } {
856
+ field: NestableWidget | Group,
857
+ ): field is Link {
858
858
  return (
859
- field.value.type === "Link" &&
860
- field.value.config?.select === "document" &&
861
- field.value.config?.customtypes !== undefined
859
+ field.type === "Link" &&
860
+ field.config?.select === "document" &&
861
+ field.config?.customtypes !== undefined
862
862
  );
863
863
  }
864
864
 
865
- function isUidField(
866
- field: TabFields[number],
867
- ): field is { key: string; value: UID } {
868
- // Filter out uid fields because it's a special field returned by the
869
- // API and is not part of the data object in the document.
870
- // We also filter by key "uid", because (as of the time of writing
871
- // this), creating any field with that API id will result in it being
872
- // used for metadata.
873
- return field.key === "uid" && field.value.type === "UID";
865
+ function mapCustomTypeStaticFields<T>(
866
+ customType: CustomType,
867
+ callback: (args: { fieldId: string; field: NestableWidget | Group }) => T,
868
+ ): T[] {
869
+ const fields: T[] = [];
870
+ for (const [_, tabFields] of Object.entries(customType.json)) {
871
+ for (const [fieldId, field] of Object.entries(tabFields)) {
872
+ if (
873
+ field.type !== "Slices" &&
874
+ field.type !== "Choice" &&
875
+ // Filter out uid fields because it's a special field returned by the
876
+ // API and is not part of the data object in the document.
877
+ // We also filter by key "uid", because (as of the time of writing
878
+ // this), creating any field with that API id will result in it being
879
+ // used for metadata.
880
+ (field.type !== "UID" || fieldId !== "uid")
881
+ ) {
882
+ fields.push(
883
+ callback({ fieldId, field: field as NestableWidget | Group }),
884
+ );
885
+ }
886
+ }
887
+ }
888
+ return fields;
889
+ }
890
+
891
+ function mapGroupFields<T>(
892
+ group: Group,
893
+ callback: (args: { fieldId: string; field: NestableWidget }) => T,
894
+ ): T[] {
895
+ if (!group.config?.fields) return [];
896
+ const fields: T[] = [];
897
+ for (const [fieldId, field] of Object.entries(group.config.fields)) {
898
+ fields.push(callback({ fieldId, field: field as NestableWidget }));
899
+ }
900
+ return fields;
874
901
  }