From faf6d94cb83ef8025929ce8801ce3db22c0b3415 Mon Sep 17 00:00:00 2001
From: Alexandre Mouton-Brady <amoutonbrady@gmail.com>
Date: Tue, 2 Feb 2021 21:57:42 +0100
Subject: [PATCH] :bug: Fix bug with createApp providers

---
 playground/index.html |  1 -
 playground/index.tsx  | 43 +++++++++++++++++++++++++++++++++++++++++--
 src/createApp.tsx     | 38 ++++++++++++++++++++++++--------------
 3 files changed, 65 insertions(+), 17 deletions(-)

diff --git a/playground/index.html b/playground/index.html
index 3a107da..58afdd2 100644
--- a/playground/index.html
+++ b/playground/index.html
@@ -3,7 +3,6 @@
   <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Document</title>
   </head>
   <body>
     <div id="app"></div>
diff --git a/playground/index.tsx b/playground/index.tsx
index 6715f39..fbc5be9 100644
--- a/playground/index.tsx
+++ b/playground/index.tsx
@@ -1,3 +1,6 @@
+import { Router, Route, RouteDefinition, Link } from 'solid-app-router';
+import { Component } from 'solid-js';
+import { MetaProvider, Title } from 'solid-meta';
 import { createApp, createStore, createGlobalState, createGlobalSignal } from '../src';
 
 const [globalState, setGlobalState] = createGlobalState({ name: 'hello' });
@@ -12,11 +15,13 @@ const [Provider, useProvider] = createStore({
 
 const Name = () => <h1>Watch me also change name here: {globalState.name}</h1>;
 
-const App = () => {
+const Home = () => {
   const [state, { inc }] = useProvider();
 
   return (
     <>
+      <Title>Home</Title>
+
       <h1>
         My name is: {globalState.name} and I'm: {globalSignal()}
       </h1>
@@ -41,4 +46,38 @@ const App = () => {
   );
 };
 
-createApp(App).use(Provider).mount('#app');
+const About = () => (
+  <>
+    <Title>About</Title>
+    <h1>About</h1>
+  </>
+);
+
+const App: Component<{ name: string }> = (props) => {
+  return (
+    <>
+      <Link href="/">Home</Link>
+      <Link href="/about">About</Link>
+      <hr />
+      <h1>Global name {props.name}</h1>
+      <Route />
+    </>
+  );
+};
+
+const routes: RouteDefinition[] = [
+  {
+    path: '/',
+    component: Home,
+  },
+  {
+    path: '/about',
+    component: About,
+  },
+];
+
+createApp(App, { name: 'Alexandre' })
+  .use(Router, { routes })
+  .use(MetaProvider)
+  .use(Provider)
+  .mount('#app');
diff --git a/src/createApp.tsx b/src/createApp.tsx
index 8c13c3e..a26a18a 100644
--- a/src/createApp.tsx
+++ b/src/createApp.tsx
@@ -1,5 +1,5 @@
-import type { JSX, Component } from 'solid-js';
-import { createComponent, render } from 'solid-js/web';
+import type { Component, JSX } from 'solid-js';
+import { createComponent as component, render } from 'solid-js/web';
 
 interface App {
   /**
@@ -19,11 +19,18 @@ interface App {
    */
   mount(domElement: HTMLElement | string): ReturnType<typeof render>;
 }
+
 interface Provider {
   provider: Component;
   opts?: Record<string, any>;
 }
 
+interface MergeParams {
+  app: (props?: Record<string, any>) => JSX.Element;
+  props: Record<string, any>;
+  providers: Provider[];
+}
+
 /**
  * This utils function automatically merge the provider in the order they
  * were provided. It turns the following calls:
@@ -49,19 +56,21 @@ interface Provider {
  *   document.querySelector('#app')
  *  )
  */
-function mergeProviders(app: () => Element, providers: Provider[]) {
-  return providers.reduceRight<JSX.Element | undefined>((application, { provider, opts }) => {
-    return createComponent(provider, {
-      ...opts,
+function mergeProviders({ app, props = {}, providers }: MergeParams) {
+  return providers.reduceRight(
+    (application, { provider, opts = {} }) => () =>
+      component(provider, {
+        ...opts,
 
-      get children() {
-        return application || createComponent(app, {});
-      },
-    });
-  }, undefined);
+        get children() {
+          return application();
+        },
+      }),
+    () => component(app, props),
+  );
 }
 
-export function createApp<T extends unknown>(app: T) {
+export function createApp<AppProps>(app: (props?: AppProps) => JSX.Element, props?: AppProps) {
   const providers: Provider[] = [];
 
   const _app: App = {
@@ -69,10 +78,11 @@ export function createApp<T extends unknown>(app: T) {
       providers.push({ provider, opts });
       return _app;
     },
+
     mount(dom) {
-      const application = mergeProviders(app as () => Element, providers);
+      const application = mergeProviders({ app, props, providers });
       const root = typeof dom === 'string' ? document.querySelector(dom) : dom;
-      return render(() => application, root);
+      return render(application, root);
     },
   };