1
1
import { z } from "zod" ;
2
2
import { nanoid } from "nanoid" ;
3
+ import { computed } from "nanostores" ;
3
4
import { useStore } from "@nanostores/react" ;
5
+ import { javascript } from "@codemirror/lang-javascript" ;
4
6
import {
5
7
type ReactNode ,
6
8
type Ref ,
@@ -13,13 +15,15 @@ import {
13
15
createContext ,
14
16
useEffect ,
15
17
useCallback ,
18
+ useMemo ,
16
19
} from "react" ;
17
20
import { CopyIcon , RefreshIcon , UpgradeIcon } from "@webstudio-is/icons" ;
18
21
import {
19
22
Box ,
20
23
Button ,
21
24
Combobox ,
22
25
DialogClose ,
26
+ DialogMaximize ,
23
27
DialogTitle ,
24
28
DialogTitleActions ,
25
29
Flex ,
@@ -58,13 +62,19 @@ import {
58
62
$userPlanFeatures ,
59
63
$instances ,
60
64
$props ,
65
+ $variableValuesByInstanceSelector ,
61
66
} from "~/shared/nano-states" ;
62
- import { $selectedInstance } from "~/shared/awareness" ;
67
+ import {
68
+ $selectedInstance ,
69
+ $selectedInstanceKeyWithRoot ,
70
+ } from "~/shared/awareness" ;
63
71
import { BindingPopoverProvider } from "~/builder/shared/binding-popover" ;
64
72
import {
73
+ EditorContent ,
65
74
EditorDialog ,
66
75
EditorDialogButton ,
67
76
EditorDialogControl ,
77
+ foldGutterExtension ,
68
78
} from "~/builder/shared/code-editor-base" ;
69
79
import { updateWebstudioData } from "~/shared/instance-utils" ;
70
80
import {
@@ -666,8 +676,8 @@ const VariablePanel = forwardRef<
666
676
direction = "column"
667
677
css = { {
668
678
overflow : "hidden" ,
679
+ padding : theme . panel . padding ,
669
680
gap : theme . spacing [ 7 ] ,
670
- p : theme . panel . padding ,
671
681
} }
672
682
>
673
683
< NameField variable = { variable } defaultValue = { variable ?. name ?? "" } />
@@ -707,6 +717,40 @@ const areAllFormErrorsVisible = (form: null | HTMLFormElement) => {
707
717
return true ;
708
718
} ;
709
719
720
+ const $instanceVariableValues = computed (
721
+ [ $selectedInstanceKeyWithRoot , $variableValuesByInstanceSelector ] ,
722
+ ( instanceKey , variableValuesByInstanceSelector ) =>
723
+ variableValuesByInstanceSelector . get ( instanceKey ?? "" ) ??
724
+ new Map < string , unknown > ( )
725
+ ) ;
726
+
727
+ const VariablePreview = ( { variable } : { variable : DataSource } ) => {
728
+ const variableValues = useStore ( $instanceVariableValues ) ;
729
+ const extensions = useMemo ( ( ) => [ javascript ( { } ) , foldGutterExtension ] , [ ] ) ;
730
+ const editorProps = {
731
+ readOnly : true ,
732
+ extensions,
733
+ // compute value as json lazily only when dialog is open
734
+ // by spliting into separate component which is invoked
735
+ // only when dialog content is rendered
736
+ value : JSON . stringify ( variableValues . get ( variable . id ) , null , 2 ) ,
737
+ onChange : ( ) => { } ,
738
+ onChangeComplete : ( ) => { } ,
739
+ } ;
740
+ return (
741
+ < Grid
742
+ align = "stretch"
743
+ css = { {
744
+ height : "100%" ,
745
+ overflow : "hidden" ,
746
+ boxSizing : "content-box" ,
747
+ } }
748
+ >
749
+ < EditorContent { ...editorProps } />
750
+ </ Grid >
751
+ ) ;
752
+ } ;
753
+
710
754
export const VariablePopoverTrigger = ( {
711
755
variable,
712
756
children,
@@ -724,6 +768,9 @@ export const VariablePopoverTrigger = ({
724
768
725
769
return (
726
770
< FloatingPanel
771
+ placement = "center"
772
+ width = { variable ? 740 : 320 }
773
+ height = { 480 }
727
774
open = { isOpen }
728
775
onOpenChange = { ( newOpen ) => {
729
776
if ( newOpen ) {
@@ -788,6 +835,7 @@ export const VariablePopoverTrigger = ({
788
835
</ Tooltip >
789
836
</ >
790
837
) }
838
+ < DialogMaximize />
791
839
< DialogClose />
792
840
</ DialogTitleActions >
793
841
}
@@ -797,57 +845,61 @@ export const VariablePopoverTrigger = ({
797
845
)
798
846
}
799
847
content = {
800
- < ScrollArea
848
+ < Grid
801
849
css = { {
802
- // flex fixes content overflowing artificial scroll area
803
- display : "flex" ,
804
- flexDirection : "column" ,
805
- width : theme . spacing [ 30 ] ,
850
+ height : "100%" ,
851
+ gridTemplateColumns : "320px 1fr" ,
806
852
} }
807
853
>
808
- < form
809
- ref = { formRef }
810
- noValidate = { true }
811
- // exclude from the flow
812
- style = { { display : "contents" } }
813
- onSubmit = { ( event ) => {
814
- event . preventDefault ( ) ;
815
- if ( isSystemVariable ) {
816
- return ;
817
- }
818
- const nameElement =
819
- event . currentTarget . elements . namedItem ( "name" ) ;
820
- // make sure only name is valid and allow to save everything else
821
- // to avoid loosing complex configuration when closed accidentally
822
- if (
823
- nameElement instanceof HTMLInputElement &&
824
- nameElement . checkValidity ( )
825
- ) {
826
- const formData = new FormData ( event . currentTarget ) ;
827
- panelRef . current ?. save ( formData ) ;
828
- // close popover whenever new variable is created
829
- // to prevent creating duplicated variable
830
- if ( variable === undefined ) {
831
- setOpen ( false ) ;
832
- }
833
- }
834
- } }
854
+ < ScrollArea
855
+ // flex fixes content overflowing artificial scroll area
856
+ css = { { display : "flex" , flexDirection : "column" } }
835
857
>
836
- { /* submit is not triggered when press enter on input without submit button */ }
837
- < button hidden > </ button >
838
- < fieldset
858
+ < form
859
+ ref = { formRef }
860
+ noValidate = { true }
861
+ // exclude from the flow
839
862
style = { { display : "contents" } }
840
- // forbid editing system variable
841
- disabled = { isSystemVariable }
863
+ onSubmit = { ( event ) => {
864
+ event . preventDefault ( ) ;
865
+ if ( isSystemVariable ) {
866
+ return ;
867
+ }
868
+ const nameElement =
869
+ event . currentTarget . elements . namedItem ( "name" ) ;
870
+ // make sure only name is valid and allow to save everything else
871
+ // to avoid loosing complex configuration when closed accidentally
872
+ if (
873
+ nameElement instanceof HTMLInputElement &&
874
+ nameElement . checkValidity ( )
875
+ ) {
876
+ const formData = new FormData ( event . currentTarget ) ;
877
+ panelRef . current ?. save ( formData ) ;
878
+ // close popover whenever new variable is created
879
+ // to prevent creating duplicated variable
880
+ if ( variable === undefined ) {
881
+ setOpen ( false ) ;
882
+ }
883
+ }
884
+ } }
842
885
>
843
- < BindingPopoverProvider
844
- value = { { containerRef : bindingPopoverContainerRef } }
886
+ { /* submit is not triggered when press enter on input without submit button */ }
887
+ < button hidden > </ button >
888
+ < fieldset
889
+ style = { { display : "contents" } }
890
+ // forbid editing system variable
891
+ disabled = { isSystemVariable }
845
892
>
846
- < VariablePanel ref = { panelRef } variable = { variable } />
847
- </ BindingPopoverProvider >
848
- </ fieldset >
849
- </ form >
850
- </ ScrollArea >
893
+ < BindingPopoverProvider
894
+ value = { { containerRef : bindingPopoverContainerRef } }
895
+ >
896
+ < VariablePanel ref = { panelRef } variable = { variable } />
897
+ </ BindingPopoverProvider >
898
+ </ fieldset >
899
+ </ form >
900
+ </ ScrollArea >
901
+ { variable && < VariablePreview variable = { variable } /> }
902
+ </ Grid >
851
903
}
852
904
>
853
905
{ children }
0 commit comments