diff --git a/src/Playground.res b/src/Playground.res index 77fc39eef..e14932207 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -1102,7 +1102,7 @@ module ControlPanel = { | CopySuccess @react.component - let make = (~createShareLink: unit => string, ~actionIndicatorKey: string) => { + let make = (~actionIndicatorKey: string) => { let (state, setState) = React.useState(() => Init) React.useEffect(() => { @@ -1112,8 +1112,7 @@ module ControlPanel = { let onClick = evt => { ReactEvent.Mouse.preventDefault(evt) - let url = createShareLink() - let ret = copyToClipboard(url) + let ret = copyToClipboard(Webapi.Window.Location.href) if ret { setState(_ => CopySuccess) } @@ -1134,7 +1133,6 @@ module ControlPanel = { } } - @val @scope(("window", "location")) external origin: string = "origin" @react.component let make = ( ~actionIndicatorKey: string, @@ -1144,46 +1142,22 @@ module ControlPanel = { ~runOutput, ~toggleRunOutput, ) => { - let router = Next.Router.useRouter() - let children = switch state { | Init => React.string("Initializing...") | SwitchingCompiler(_ready, _version) => React.string("Switching Compiler...") - | Compiling(ready, _) - | Ready(ready) => + | Compiling(_, _) + | Ready(_) => let onFormatClick = evt => { ReactEvent.Mouse.preventDefault(evt) dispatch(Format(editorCode.current)) } - let createShareLink = () => { - let params = switch ready.targetLang { - | Res => [] - | lang => [("ext", Api.Lang.toExt(lang))] - } - - let version = ready.selected.compilerVersion - - Array.push(params, ("version", "v" ++ version))->ignore - - Array.push( - params, - ("code", editorCode.current->LzString.compressToEncodedURIComponent), - )->ignore - - let querystring = params->Array.map(((key, value)) => key ++ "=" ++ value)->Array.join("&") - - let url = origin ++ router.route ++ "?" ++ querystring - Next.Router.replace(router, url) - url - } -
toggleRunOutput()}> {React.string("Auto-run")} - +
| _ => React.null } @@ -1455,6 +1429,8 @@ let make = (~versions: array) => { | _ => Api.Lang.Res } + let initialModuleSystem = Dict.get(router.query, "module") + let initialContent = switch (Dict.get(router.query, "code"), initialLang) { | (Some(compressedCode), _) => LzString.decompressToEncodedURIComponent(compressedCode) | (None, Reason) => initialReContent @@ -1473,6 +1449,7 @@ let make = (~versions: array) => { let onAction = _ => setActionCount(prev => prev > 1000000 ? 0 : prev + 1) let (compilerState, compilerDispatch) = useCompilerManager( ~initialVersion?, + ~initialModuleSystem?, ~initialLang, ~onAction, ~versions, diff --git a/src/bindings/Next.resi b/src/bindings/Next.resi deleted file mode 100644 index 2af334399..000000000 --- a/src/bindings/Next.resi +++ /dev/null @@ -1,135 +0,0 @@ -module GetServerSideProps: { - module Req: { - type t - } - - module Res: { - type t - - let setHeader: (t, string, string) => unit - let write: (t, string) => unit - let end_: t => unit - } - - // See: https://github.com/zeit/next.js/blob/canary/packages/next/types/index.d.ts - type context<'props, 'params> = { - params: 'params, - query: Dict.t, - req: Req.t, - res: Res.t, - } - - type t<'props, 'params> = context<'props, 'params> => promise<{"props": 'props}> -} - -module GetStaticProps: { - // See: https://github.com/zeit/next.js/blob/canary/packages/next/types/index.d.ts - type context<'props, 'params> = { - params: 'params, - query: Dict.t, - req: Nullable.t<'props>, - } - - type t<'props, 'params> = context<'props, 'params> => promise<{"props": 'props}> - - type revalidate<'props, 'params> = context<'props, 'params> => promise<{ - "props": 'props, - "revalidate": Nullable.t, - }> -} - -module GetStaticPaths: { - // 'params: dynamic route params used in dynamic routing paths - // Example: pages/[id].js would result in a 'params = { id: string } - type path<'params> = {params: 'params} - - type return<'params> = { - paths: array>, - fallback: bool, - } - - type t<'params> = unit => promise> -} - -module Link: { - @react.component - let make: ( - ~href: string, - ~_as: string=?, - ~prefetch: bool=?, - ~replace: bool=?, - ~shallow: bool=?, - ~passHref: bool=?, - ~children: React.element, - ~className: string=?, - ~target: string=?, - ) => React.element -} - -module Router: { - /* - Make sure to only register events via a useEffect hook! - */ - module Events: { - type t - - let on: ( - t, - [ - | #routeChangeStart(string => unit) - | #routeChangeComplete(string => unit) - | #hashChangeComplete(string => unit) - ], - ) => unit - - let off: ( - t, - [ - | #routeChangeStart(string => unit) - | #routeChangeComplete(string => unit) - | #hashChangeComplete(string => unit) - ], - ) => unit - } - - type router = { - route: string, - asPath: string, - events: Events.t, - pathname: string, - query: Dict.t, - } - - type pathObj = { - pathname: string, - query: Dict.t, - } - - let push: (router, string) => unit - let pushObj: (router, pathObj) => unit - - let useRouter: unit => router - - let replace: (router, string) => unit - let replaceObj: (router, pathObj) => unit -} - -module Head: { - @react.component - let make: (~children: React.element) => React.element -} - -module Error: { - @react.component - let make: (~statusCode: int, ~children: React.element) => React.element -} - -module Dynamic: { - type options = {ssr?: bool, loading?: unit => React.element} - - @module("next/dynamic") - external dynamic: (unit => promise<'a>, options) => 'a = "default" - - @val - external import: string => promise<'a> = "import" -} diff --git a/src/bindings/Webapi.res b/src/bindings/Webapi.res index a3a053279..c25856ec2 100644 --- a/src/bindings/Webapi.res +++ b/src/bindings/Webapi.res @@ -48,6 +48,17 @@ module Window = { @scope("window") @val external innerWidth: int = "innerWidth" @scope("window") @val external innerHeight: int = "innerHeight" @scope("window") @val external scrollY: int = "scrollY" + + module History = { + @scope(("window", "history")) @val + external pushState: (nullable<'a>, @as(json`""`) _, ~url: string=?) => unit = "pushState" + @scope(("window", "history")) @val + external replaceState: (nullable<'a>, @as(json`""`) _, ~url: string=?) => unit = "replaceState" + } + + module Location = { + @scope(("window", "location")) @val external href: string = "href" + } } module Fetch = { diff --git a/src/common/CompilerManagerHook.res b/src/common/CompilerManagerHook.res index bebf9634a..ddff4b789 100644 --- a/src/common/CompilerManagerHook.res +++ b/src/common/CompilerManagerHook.res @@ -242,6 +242,21 @@ type action = | CompileCode(Lang.t, string) | UpdateConfig(Config.t) +let createUrl = (pathName, ready) => { + let params = switch ready.targetLang { + | Res => [] + | lang => [("ext", RescriptCompilerApi.Lang.toExt(lang))] + } + Array.push(params, ("version", "v" ++ ready.selected.compilerVersion)) + Array.push(params, ("module", ready.selected.config.module_system)) + Array.push(params, ("code", ready.code->LzString.compressToEncodedURIComponent)) + let querystring = params->Array.map(((key, value)) => key ++ "=" ++ value)->Array.join("&") + let url = pathName ++ "?" ++ querystring + url +} + +let defaultModuleSystem = "esmodule" + // ~initialLang: // The target language the compiler should be set to during // playground initialization. If the compiler doesn't support the language, it @@ -255,12 +270,14 @@ type action = // cases where the output didn't visually change) let useCompilerManager = ( ~initialVersion: option=?, + ~initialModuleSystem=defaultModuleSystem, ~initialLang: Lang.t=Res, ~onAction: option unit>=?, ~versions: array, (), ) => { let (state, setState) = React.useState(_ => Init) + let router = Next.Router.useRouter() // Dispatch method for the public interface let dispatch = (action: action): unit => { @@ -417,7 +434,7 @@ let useCompilerManager = ( // internal compiler state with our playground state. let config = { ...instance->Compiler.getConfig, - module_system: "esmodule", + module_system: initialModuleSystem, ?open_modules, } instance->Compiler.setConfig(config) @@ -470,7 +487,11 @@ let useCompilerManager = ( let apiVersion = apiVersion->Version.fromString let open_modules = getOpenModules(~apiVersion, ~libraries) - let config = {...instance->Compiler.getConfig, ?open_modules} + let config = { + ...instance->Compiler.getConfig, + module_system: defaultModuleSystem, + ?open_modules, + } instance->Compiler.setConfig(config) let selected = { @@ -528,8 +549,10 @@ let useCompilerManager = ( } setState(_ => Ready({...ready, result: FinalResult.Comp(compResult)})) - | SetupFailed(_) - | Ready(_) => () + | SetupFailed(_) => () + | Ready(ready) => + let url = createUrl(router.route, ready) + Webapi.Window.History.replaceState(null, ~url) } } diff --git a/src/common/CompilerManagerHook.resi b/src/common/CompilerManagerHook.resi index ac29d6e4d..f2880d321 100644 --- a/src/common/CompilerManagerHook.resi +++ b/src/common/CompilerManagerHook.resi @@ -59,8 +59,11 @@ type action = let useCompilerManager: ( ~initialVersion: Semver.t=?, + ~initialModuleSystem: string=?, ~initialLang: Lang.t=?, ~onAction: action => unit=?, ~versions: array, unit, ) => (state, action => unit) + +let createUrl: (string, ready) => string