@@ -3,8 +3,8 @@ import equal from "react-fast-compare"
3
3
4
4
import { Formex , FormexController , getIn , useCreateFormex } from "@firecms/formex" ;
5
5
import {
6
- DEFAULT_FIELD_CONFIGS ,
7
6
ConfirmationDialog ,
7
+ DEFAULT_FIELD_CONFIGS ,
8
8
getFieldConfig ,
9
9
getFieldId ,
10
10
isPropertyBuilder ,
@@ -17,15 +17,21 @@ import {
17
17
} from "@firecms/core" ;
18
18
import {
19
19
Button ,
20
+ Card ,
20
21
cls ,
21
22
DeleteIcon ,
22
23
Dialog ,
23
24
DialogActions ,
24
25
DialogContent ,
26
+ DialogTitle ,
27
+ fieldBackgroundDisabledMixin ,
28
+ fieldBackgroundHoverMixin ,
29
+ fieldBackgroundMixin ,
25
30
IconButton ,
26
31
InfoLabel ,
27
- Select ,
28
- Typography
32
+ Tooltip ,
33
+ Typography ,
34
+ WarningOffIcon
29
35
} from "@firecms/ui" ;
30
36
import { EnumPropertyField } from "./properties/EnumPropertyField" ;
31
37
import { StoragePropertyField } from "./properties/StoragePropertyField" ;
@@ -42,7 +48,6 @@ import { AdvancedPropertyValidation } from "./properties/advanced/AdvancedProper
42
48
import { editableProperty } from "../../utils/entities" ;
43
49
import { KeyValuePropertyField } from "./properties/KeyValuePropertyField" ;
44
50
import { updatePropertyFromWidget } from "./utils/update_property_for_widget" ;
45
- import { PropertySelectItem } from "./PropertySelectItem" ;
46
51
import { UrlPropertyField } from "./properties/UrlPropertyField" ;
47
52
import { supportedFields } from "./utils/supported_fields" ;
48
53
import { MarkdownPropertyField } from "./properties/MarkdownPropertyField" ;
@@ -342,12 +347,6 @@ function PropertyEditFormFields({
342
347
const [ deleteDialogOpen , setDeleteDialogOpen ] = useState ( false ) ;
343
348
const [ selectedFieldConfigId , setSelectedFieldConfigId ] = useState < string | undefined > ( values ?. dataType ? getFieldId ( values ) : undefined ) ;
344
349
345
- const allSupportedFields = Object . entries ( supportedFields ) . concat ( Object . entries ( propertyConfigs ) ) ;
346
-
347
- const displayedWidgets = inArray
348
- ? allSupportedFields . filter ( ( [ _ , propertyConfig ] ) => ! isPropertyBuilder ( propertyConfig . property ) && propertyConfig . property ?. dataType !== "array" )
349
- : allSupportedFields ;
350
-
351
350
const deferredValues = useDeferredValue ( values ) ;
352
351
const nameFieldRef = useRef < HTMLInputElement > ( null ) ;
353
352
@@ -489,62 +488,17 @@ function PropertyEditFormFields({
489
488
490
489
< div className = "flex mt-2 justify-between" >
491
490
< div className = { "w-full flex flex-col gap-2" } >
492
- < Select
493
- // className={"w-full"}
494
- error = { Boolean ( selectedWidgetError ) }
495
- value = { selectedFieldConfigId ?? "" }
496
- placeholder = { "Select a property widget" }
491
+ < WidgetSelectView
492
+ initialProperty = { values }
493
+ value = { selectedFieldConfigId as PropertyConfigId }
494
+ onValueChange = { ( value ) => onWidgetSelectChanged ( value as PropertyConfigId ) }
497
495
open = { selectOpen }
498
496
onOpenChange = { setSelectOpen }
499
- position = { "item-aligned" }
500
497
disabled = { disabled }
501
- renderValue = { ( value ) => {
502
- if ( ! value ) {
503
- return < em > Select a property
504
- widget</ em > ;
505
- }
506
- const key = value as PropertyConfigId ;
507
- const propertyConfig = DEFAULT_FIELD_CONFIGS [ key ] ?? propertyConfigs [ key ] ;
508
- const baseProperty = propertyConfig . property ;
509
- const baseFieldConfig = baseProperty && ! isPropertyBuilder ( baseProperty ) ? getFieldConfig ( baseProperty , propertyConfigs ) : undefined ;
510
- const optionDisabled = isPropertyBuilder ( baseProperty ) || ( existing && baseProperty . dataType !== values ?. dataType ) ;
511
- const computedFieldConfig = baseFieldConfig ? mergeDeep ( baseFieldConfig , propertyConfig ) : propertyConfig ;
512
- return < div
513
- onClick = { ( e ) => {
514
- if ( optionDisabled ) {
515
- e . stopPropagation ( ) ;
516
- e . preventDefault ( ) ;
517
- }
518
- } }
519
- className = { cls (
520
- "flex items-center" ,
521
- optionDisabled ? "w-full pointer-events-none opacity-50" : "" ) } >
522
- < div className = { "mr-8" } >
523
- < PropertyConfigBadge propertyConfig = { computedFieldConfig } />
524
- </ div >
525
- < div className = { "flex flex-col items-start text-base text-left" } >
526
- < div > { computedFieldConfig . name } </ div >
527
- < Typography variant = { "caption" }
528
- color = { "disabled" } >
529
- { optionDisabled ? "You can only switch to widgets that use the same data type" : computedFieldConfig . description }
530
- </ Typography >
531
- </ div >
532
- </ div >
533
- } }
534
- onValueChange = { ( value ) => {
535
- onWidgetSelectChanged ( value as PropertyConfigId ) ;
536
- } } >
537
- { displayedWidgets . map ( ( [ key , propertyConfig ] ) => {
538
- const baseProperty = propertyConfig . property ;
539
- const optionDisabled = existing && ! isPropertyBuilder ( baseProperty ) && baseProperty . dataType !== values ?. dataType ;
540
- return < PropertySelectItem
541
- key = { key }
542
- value = { key }
543
- optionDisabled = { optionDisabled }
544
- propertyConfig = { propertyConfig }
545
- existing = { existing } /> ;
546
- } ) }
547
- </ Select >
498
+ showError = { Boolean ( selectedWidgetError ) }
499
+ existing = { existing }
500
+ propertyConfigs = { propertyConfigs }
501
+ inArray = { inArray } />
548
502
549
503
{ selectedWidgetError &&
550
504
< Typography variant = "caption"
@@ -588,10 +542,10 @@ function PropertyEditFormFields({
588
542
onCancel = { ( ) => setDeleteDialogOpen ( false ) }
589
543
title = { < div > Delete this property?</ div > }
590
544
body = {
591
- < div > This will < b > not delete any
592
- data</ b > , only modify the
593
- collection.</ div >
594
- } /> }
545
+ < div > This will < b > not delete any
546
+ data</ b > , only modify the
547
+ collection.</ div >
548
+ } /> }
595
549
596
550
</ >
597
551
) ;
@@ -621,3 +575,168 @@ function validateName(value: string) {
621
575
}
622
576
return error ;
623
577
}
578
+
579
+ const WIDGET_TYPE_MAP = {
580
+ text_field : "Text" ,
581
+ multiline : "Text" ,
582
+ markdown : "Text" ,
583
+ url : "Text" ,
584
+ email : "Text" ,
585
+ switch : "Boolean" ,
586
+ select : "Select" ,
587
+ multi_select : "Select" ,
588
+ number_input : "Number" ,
589
+ number_select : "Select" ,
590
+ multi_number_select : "Select" ,
591
+ file_upload : "File" ,
592
+ multi_file_upload : "File" ,
593
+ reference : "Reference" ,
594
+ multi_references : "Reference" ,
595
+ date_time : "Date" ,
596
+ group : "Group" ,
597
+ key_value : "Key-Value" ,
598
+ repeat : "Repeat" ,
599
+ custom_array : "Array" ,
600
+ block : "Block"
601
+ } ;
602
+
603
+ function WidgetSelectView ( {
604
+ initialProperty,
605
+ value,
606
+ onValueChange,
607
+ open,
608
+ onOpenChange,
609
+ disabled,
610
+ showError,
611
+ existing,
612
+ propertyConfigs,
613
+ inArray
614
+ } : {
615
+ initialProperty ?: PropertyWithId ,
616
+ value ?: PropertyConfigId ,
617
+ onValueChange : ( value : string ) => void ,
618
+ showError : boolean ,
619
+ open : any ,
620
+ onOpenChange : any ,
621
+ disabled : boolean ,
622
+ existing : boolean ,
623
+ propertyConfigs : Record < string , PropertyConfig > ,
624
+ inArray ?: boolean
625
+ } ) {
626
+
627
+ const allSupportedFields = Object . entries ( supportedFields ) . concat ( Object . entries ( propertyConfigs ) ) ;
628
+
629
+ const displayedWidgets = inArray
630
+ ? allSupportedFields . filter ( ( [ _ , propertyConfig ] ) => ! isPropertyBuilder ( propertyConfig . property ) && propertyConfig . property ?. dataType !== "array" )
631
+ : allSupportedFields ;
632
+
633
+ const key = value ;
634
+ const propertyConfig = key ? ( DEFAULT_FIELD_CONFIGS [ key ] ?? propertyConfigs [ key ] ) : undefined ;
635
+ const baseProperty = propertyConfig ?. property ;
636
+ const baseFieldConfig = baseProperty && ! isPropertyBuilder ( baseProperty ) ? getFieldConfig ( baseProperty , propertyConfigs ) : undefined ;
637
+ const computedFieldConfig = baseFieldConfig && propertyConfig ? mergeDeep ( baseFieldConfig , propertyConfig ) : propertyConfig ;
638
+
639
+ return < >
640
+ < div
641
+ onClick = { ( ) => {
642
+ if ( ! disabled ) {
643
+ onOpenChange ( ! open ) ;
644
+ }
645
+ } }
646
+ className = { cls (
647
+ "select-none rounded-md text-sm p-4" ,
648
+ fieldBackgroundMixin ,
649
+ disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin ,
650
+ "relative flex items-center" ,
651
+ ) } >
652
+ { ! value && < em > Select a property widget</ em > }
653
+ { value && computedFieldConfig && < div
654
+ className = { cls (
655
+ "flex items-center" ) } >
656
+ < div className = { "mr-8" } >
657
+ < PropertyConfigBadge propertyConfig = { computedFieldConfig } />
658
+ </ div >
659
+ < div className = { "flex flex-col items-start text-base text-left" } >
660
+ < div > { computedFieldConfig . name } </ div >
661
+ < Typography variant = { "caption" }
662
+ color = { "secondary" } >
663
+ { computedFieldConfig . description }
664
+ </ Typography >
665
+ </ div >
666
+ </ div > }
667
+ </ div >
668
+ < Dialog open = { open }
669
+ onOpenChange = { onOpenChange }
670
+ maxWidth = { "4xl" } >
671
+ < DialogTitle >
672
+ Select a property widget
673
+ </ DialogTitle >
674
+ < DialogContent >
675
+ < div className = { "grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 mt-4" } >
676
+ { displayedWidgets . map ( ( [ key , propertyConfig ] ) => {
677
+ return < WidgetSelectViewItem
678
+ key = { key }
679
+ initialProperty = { initialProperty }
680
+ onClick = { ( ) => {
681
+ onValueChange ( key ) ;
682
+ onOpenChange ( false ) ;
683
+ } }
684
+ propertyConfig = { propertyConfig }
685
+ existing = { existing } /> ;
686
+ } ) }
687
+ </ div >
688
+ </ DialogContent >
689
+ </ Dialog >
690
+ </ > ;
691
+ }
692
+
693
+ export interface PropertySelectItemProps {
694
+ onClick ?: ( ) => void ;
695
+ initialProperty ?: PropertyWithId ;
696
+ propertyConfig : PropertyConfig ;
697
+ existing : boolean ;
698
+ }
699
+
700
+ export function WidgetSelectViewItem ( {
701
+ onClick,
702
+ initialProperty,
703
+ // optionDisabled,
704
+ propertyConfig,
705
+ existing
706
+ } : PropertySelectItemProps ) {
707
+ const baseProperty = propertyConfig . property ;
708
+ const shouldWarnChangingDataType = existing && ! isPropertyBuilder ( baseProperty ) && baseProperty . dataType !== initialProperty ?. dataType ;
709
+
710
+ return < Card
711
+ onClick = { onClick }
712
+ // disabled={optionDisabled}
713
+ className = { "flex flex-row items-center px-4 py-2" } >
714
+ < div
715
+ className = { cls (
716
+ "flex flex-row items-center text-base min-h-[48px]" ,
717
+ // optionDisabled ? "w-full" : ""
718
+ ) } >
719
+ < div className = { "mr-8" } >
720
+ < PropertyConfigBadge propertyConfig = { propertyConfig } disabled = { ! shouldWarnChangingDataType } />
721
+ </ div >
722
+ < div >
723
+ < div className = { "flex flex-row gap-2 items-center" } >
724
+ { shouldWarnChangingDataType && < Tooltip
725
+ title = { "This widget uses a different data type than the initially selected widget. This can cause errors with existing data." } >
726
+ < WarningOffIcon size = "smallest" className = { "w-4" } />
727
+ </ Tooltip > }
728
+ < Typography
729
+ color = { shouldWarnChangingDataType ? "secondary" : undefined } > { propertyConfig . name } </ Typography >
730
+ </ div >
731
+ < Typography variant = { "caption" }
732
+ color = { "secondary" }
733
+ className = { "max-w-sm" } >
734
+ { propertyConfig . description }
735
+
736
+ { /*{existing && optionDisabled ? "You can only switch to widgets that use the same data type" : propertyConfig.description}*/ }
737
+ </ Typography >
738
+
739
+ </ div >
740
+ </ div >
741
+ </ Card >
742
+ }
0 commit comments