diff --git a/README.md b/README.md
index fa3d64a85074e5f096523bc950112c98b17b63a4..2646c499a9fec685a5b875a05d863779f282ba11 100644
--- a/README.md
+++ b/README.md
@@ -3,48 +3,367 @@
 </div>
 
 | [![MIT license](https://img.shields.io/badge/license-MIT-e51879.svg)](https://gitlab.coko.foundation/wax/wax-prosemirror/raw/master/LICENSE) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) |
-| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+
 
 This application is being developed by the [Coko Foundation](https://coko.foundation/), for the [University of California Press](http://www.ucpress.edu/) as part of the [Editoria](https://gitlab.coko.foundation/editoria/editoria/) application.
 
-Wax Editor is build against Prosemirror libraries. Check Prosemirror [website](https://prosemirror.net/) and [GitHub repo](https://github.com/ProseMirror) for more information. 
+Wax Editor is build against Prosemirror libraries. Check Prosemirror [website](https://prosemirror.net/) and [GitHub repo](https://github.com/ProseMirror) for more information.
+
+Wax depends on the following libraries.
+
+* React for the view(ui)
+
+* Styled-components for theming and styling.
+
+* Inversify.io as service containers
 
 ## Introduction
 
-Wax is a Monorepo that consists of several packages.
+### Editor Props
+
+```javascript
+autoFocus; // sets cursor in the begging of the document
+onChange; // when the editor's surface is updated (perform an action ex. save)
+value; // the actual HTML content of the editor
+fileUpload; // used for uploading images (should return a promise with the actual file path)
+placeholder; // a placeholder used for empty documents
+config; // adds on the editor anything from new services, tools, Pmpplugins etc. Check editoria config (link)
+readonly; // editor in in read-only mode
+onBlur; // on focus lost
+layout; // used to create your own Layout using React components
+```
+
+**Current Tools and Toolgroups:**
+
+1.  _Base Tool group_: `undo`, `redo`, `save`
+
+2.  _Inline Annotations Tool group_: `strong`, `italic`, `link`, `strikethrough`, `underline`, `subscript`, `superscript`, `small caps`
+
+3.  _Lists Tool group_: `numbered list`, `bullet list`
+
+4.  _Image Tool group_: `image`
+
+5.  _Table Tool group_: `create table`, edit table dropdown that includes: `insert/delete row`, `insert/delete column` ,`merge cells`, `split cell`, `delete table`, `Toggle header column`, `Toggle header row`
+
+6.  _Display Tool group_: `Title`, `Author`, `Subtitle`, `Epigraph Prose`, `Epigraph Poetry`, `Heading 1`, `Heading 2`, `Heading 3`
+
+7.  _Text Tool group_: `Paragraph`, `Paragraph Continued`, `Extract Prose`, `Extract Poetry`, `Source Note`, `Block Quote`
+
+<h2> wax-prosemirror-core </h2>
+
+The role of wax-core is
+
+* Mount a prosemirror instance
+
+* Initiate default services (link)
+
+  1.  LayoutService
+
+  2.  SchemaService
 
-<h3> wax-prosemirror-core </h3>
+  3.  MenuService
 
-Core holds all the funcionality of 
+  4.  RulesService
 
-<h3> wax-prosemirror-schema </h3>
+  5.  ShortCutsService
 
-Schema consists of all the different nodes/marks currently supported by the editor.
+A big part of wax-core is the application layer(link), which is responsible for the application’s lifecycle by registering and booting services, merging configs, using the schema
+and gathering all prosemirror plugins.
+For more information about Default Services and services in general visit (link)
 
-<h3> wax-prosemirror-components </h3>
+Also holds some default prosemirror plugins that are necessary like the dropCursor, gapCursor, history and some optional as the placeholder.
 
-React components
+<h2> wax-prosemirror-schema </h2>
 
-<h3> wax-prosemirror-themes </h3>
+Holds all the nodes and marks currently supported by Wax. You can either have a node/mark in “Wax node/mark structure” or a default prosemirror node/mark.
+For more information on how a Wax node/mark is different check the SchemaService(link)
 
-<h3> wax-prosemirror-layouts </h3>
+<h2> wax-prosemirror-components </h2>
+
+React components to support various features of the editor from buttons to overlays to comment discussions etc. right now really basic (link)
+
+<h2> wax-prosemirror-themes </h2>
+ Holds the different themes of the editor. Check the option in the CokoTheme (link)
+
+<h2> wax-prosemirror-layouts </h2>
+Holds different layouts of the editor. Through the layout service you can configure the areas of different components (as an example see EditoriaLayout -link-)
+
+<h2> wax-prosemirror-utilities </h2>
+ Various helpers methods for prosemirror...
+
+  <h2> Editors </h2>
 
-<h3> wax-prosemirror-utilities </h3>
- 
- <h3> Editors </h3>
- 
  Editors are private pakages inside the monorepo, for development/demo purposes.
 
+ <h2> wax-prosemirror-services</h2>
+ Service providers are the central place of Wax bootstrapping. Your own services, as well as all of Wax's core services are bootstrapped via application provider and are initiated before everything else.
+
+But, what do we mean by "bootstrapped"? In general, we mean registering things, including registering service container bindings and event listeners. Service providers are the central place to configure your application.
+
+If you open [editoria's config file](https://gitlab.coko.foundation/wax/wax-prosemirror/blob/wax-plugins/editors/editoria/src/config/config.js),
+you will see the config file where you can configure the extra services (apart from those Wax will load on init) of your editor.
+These are all of the service provider classes that will be loaded for your application.
+
+In the following overview we will see how to write our own service providers and register them within the Editor.
+
+<h3>Writing Service Providers</h2>
+
+All service providers extend the [Service](https://gitlab.coko.foundation/wax/wax-prosemirror/blob/wax-plugins/wax-prosemirror-core/src/services/Service.js) class. Most service providers contain a register and a boot method. Within the register method, you should only bind things into the service container.
+
+<h3>The Register Method</h3>
+
+Let’s take a look at a simple service like the StrongService. Within any of your service provider methods, you always have access to the config and schema properties and also you have access to the service container using [inversify.io](http://inversify.io/).
+
+```javascript
+import { toggleMark } from "prosemirror-commands";
+import Service from "wax-prosemirror-core/src/services/Service";
+import { strongMark } from "wax-prosemirror-schema";
+import Strong from "./Strong";
+
+class StrongService extends Service {
+  boot() {
+    const shortCuts = this.container.get("ShortCuts");
+    shortCuts.addShortCut({ "Mod-b": toggleMark(this.schema.marks.strong) });
+  }
+
+  register() {
+    this.container.bind("Strong").to(Strong);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        strong: strongMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default StrongService;
+```
+
+This service provider defines a register method, it registers a class and in this case is the strong tool. For more information on how to use service container check inversify.io documentation.
+
+A slightly more complicated example could be the ShortCutsService register method.
+
+```javascript
+register() {
+    const PmPlugins = this.app.PmPlugins;
+    this.container
+      .bind("ShortCuts")
+      .toDynamicValue(() => {
+        const { schema: { schema } } = this.app;
+
+        return new ShortCuts(PmPlugins, schema);
+      })
+      .inSingletonScope();
+  }
+```
+
+In the above example we bind ShortCuts to a factory method which injects PmPlugins and schema into ShortCuts class.
+
+### The Boot Method
+
+So, what if we need to register a view component within our service provider? This should be done within the boot method. This method is called after all other service providers have been registered, meaning you have access to all other services that have been registered.
+
+In the StrongService when the boot method is called all other services will have been registered, so we get the ShortCuts Service and execute a method for registering a new ShortCut.
+
+Another example could be the MenuSerivce (link)
+
+```javascript
+boot() {
+    const { menus } = this.container.get("MenuCollection");
+    const layout = this.container.get("Layout");
+    menus.forEach(menu => {
+      layout.addComponent(menu.config.templateArea, menu.render());
+    });
+  }
+```
+
+In Menu’s boot method we get Layout and we add components to the already defined areas from our Layout.
+
+### Extra functionalities include
+
+1.  Registering Services from within a Service.
+
+```javascript
+class InlineAnnotationsService extends Service {
+  dependencies = [
+    new CodeService(),
+    new StrongService(),
+    new EmphasisService(),
+    new SubscriptService(),
+    new SuperscriptService(),
+    new StrikeThroughService(),
+    new UnderlineService(),
+    new SmallCapsService()
+  ];
+}
+```
+
+2.  Within any of your service provider methods, you always have access to the app, config properties .
+3.  Dependant functionality between services. An example of the dependency between two services is linkService(link) and OverLayService (links) where OverLayService registers a function
+    that adds a component to the overlay area and LinkService calls OverLay and adds it’s component. ShortCut Service could be another example where each of the services like Strong, paragraph etc can call it to add a shortcut.
+
+## Core Services
+
+### SchemaService
+
+Schema service enable us to add marks and nodes into prosemirror. We have two functions for that scope CreateNode and CreateMark.
+In prosemirror all attributes are in the node so you might have on the same node a class , href, user attribute etc. This attributes might be used from different services.
+
+So for example on the pararaph node Service A adds the class attribute while Service B adds the user attribute.
+If you only use Service A the user attribute still exists in the schema for that node.
+So if we want to add the user attribute only through service B , we have “toWaxSchema” option .
+
+Service A register method.
+
+```javascript
+CreateNode(
+  {
+    paragraph: {
+      group: "block",
+      content: "inline*",
+      attrs: {
+        class: { default: "paragraph" }
+      },
+      parseDOM: {
+        tag: "p.paragraph",
+        getAttrs(hook, next) {
+          Object.assign(hook, {
+            class: hook.dom.getAttribute("class")
+          });
+          next();
+        }
+      },
+      toDOM(hook, next) {
+        const attrs = { class: hook.node.attrs.class };
+
+        hook.value = ["p", attrs, 0];
+        next();
+      }
+    }
+  },
+  { toWaxSchema: true }
+);
+```
+
+Service B register method.
+
+```javascript
+CreateNode(
+  {
+    paragraph: {
+      group: "block",
+      content: "inline*",
+      attrs: {
+        user: { default: [] }
+      },
+      parseDOM: {
+        tag: "p.paragraph",
+        getAttrs(hook, next) {
+          Object.assign(hook, {
+            user: parseUser(hook.dom.dataset.user)
+          });
+          next();
+        }
+      },
+      toDOM(hook, next) {
+        Object.assign(hook.value[1], {
+          "data-user": JSON.stringify(hook.node.attrs.user)
+        });
+        next();
+      }
+    }
+  },
+  { toWaxSchema: true }
+);
+```
+
+If the above 2 services are registed SchemaService will merge those 2 nodes into a single prosemirror one having both attributes.
+
+LayoutService
+
+This service enables us to set a layout for the editor. Internally Wax calls the setLayout method to apply a layout. How can you write your own layout. (link editoria layout).
+
+A layout is a react component which has a prop the mounted prosemirror instance in order to place within the layout. You can also have your own “Areas”. For example in EditoriaLayout we have the following
+
+```javascript
+const LeftSideBar = componentPlugin("leftSideBar");
+const RightSideBar = componentPlugin("rightSideBar");
+const TopBar = componentPlugin("topBar");
+const BottomBar = componentPlugin("bottomBar");
+const WaxOverlays = componentPlugin("waxOverlays");
+
+const EditoriaLayout = ({ editor }) => {
+  return (
+    <ThemeProvider theme={cokoTheme}>
+      <LayoutWrapper>
+        <MainMenuContainer>
+          <MainMenuInner>
+            <TopBar />
+          </MainMenuInner>
+        </MainMenuContainer>
+        <WaxSurfaceContainer>
+          <SideMenuContainer>
+            <SideMenuInner>
+              <LeftSideBar />
+            </SideMenuInner>
+          </SideMenuContainer>
+          <WaxSurfaceScroll className="wax-surface-scroll">
+            {editor}
+            <WaxOverlays />
+          </WaxSurfaceScroll>
+          <RightSideBar />
+        </WaxSurfaceContainer>
+        <BottomBar />
+        <InfoArea />
+      </LayoutWrapper>
+    </ThemeProvider>
+  );
+};
+```
+
+`<LeftSideBar />` is placed accordingly to our design in the left of the editor as ui element.
+So we define a “leftSideBar” area. Area is like a “tag” for the editor so it knows where to place certain components. So by defining the leftSideBar Area we can use that area in our services to add components into it.
+
+An example of using areas in editoria config.
+
+```javascript
+MenuService: [
+    {
+      templateArea: "topBar",
+      toolGroups: ["Base", "Annotations", "Lists", "Images", "Tables"]
+    },
+    {
+      templateArea: "leftSideBar",
+      toolGroups: ["Display"]
+    }
+  ],
+```
+
+Lastly Layout has a core method which is called ComponentPlugin. Is used in order to render the components to the area and to provide the view state of the editor in order to get updates.
+
+### ShortCuts Service
+
+**TO DO**
+
+### Rules Service
+
+**TO DO**
+
+### Menu Service
+
+Is used for adding menus to the editor. **TO DO How to create a group/tool and add it to the menu.**
+
 ## Get up and running
 
 Run a local version of the editor
-  
-1)  `git@gitlab.coko.foundation:wax/wax-prosemirror.git`
-  
-2) `yarn with node > 11`
-  
-3) `yarn editoria` Will bring up a demo of the Editoria Ediitor
-
-4) `yarn default` Will bring up a basic version will only an editing surface accepting paragragraphs
+
+1.  `git@gitlab.coko.foundation:wax/wax-prosemirror.git`
+
+2.  `yarn with node > 11`
+
+3.  `yarn editoria` Will bring up a demo of the Editoria Ediitor
 
 Scripts: `yarn` , `yarn clean`, `yarn reset`
diff --git a/editors/default/config-overrides.js b/editors/default/config-overrides.js
index 82c74c17dd0161dd58670ef1a2c591870a92e789..e2cf94482e8e7bc53cdb65bef9c758bbf04a1a3e 100644
--- a/editors/default/config-overrides.js
+++ b/editors/default/config-overrides.js
@@ -12,7 +12,11 @@ module.exports = function override(config, env) {
                 [require("@babel/preset-env"), { modules: false }],
                 require("@babel/preset-react")
               ],
-              plugins: [require("@babel/plugin-proposal-class-properties")]
+              plugins: [
+                ["@babel/plugin-proposal-decorators", { legacy: true }],
+                "babel-plugin-parameter-decorator",
+                ["@babel/plugin-proposal-class-properties", { loose: true }]
+              ]
             }
           },
           {
diff --git a/editors/default/jsconfig.json b/editors/default/jsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..504cd646e14906b4db8e943f9bfb10ab80162cee
--- /dev/null
+++ b/editors/default/jsconfig.json
@@ -0,0 +1,5 @@
+{
+  "compilerOptions": {
+    "experimentalDecorators": true
+  }
+}
diff --git a/editors/default/package.json b/editors/default/package.json
index 8da544d5e5c02ea25836592451b1a1625cf09306..4804d076ae465117a79009565e3f743227cf2058 100644
--- a/editors/default/package.json
+++ b/editors/default/package.json
@@ -9,8 +9,8 @@
     "wax-prosemirror-components": "^0.0.3",
     "wax-prosemirror-core": "^0.0.3",
     "wax-prosemirror-layouts": "^0.0.3",
-    "wax-prosemirror-schema": "^0.0.3",
-    "wax-prosemirror-themes": "^0.0.3"
+    "wax-prosemirror-themes": "^0.0.3",
+    "babel-plugin-parameter-decorator": "1.0.12"
   },
   "scripts": {
     "start": "react-app-rewired start",
@@ -21,12 +21,7 @@
   "eslintConfig": {
     "extends": "react-app"
   },
-  "browserslist": [
-    ">0.2%",
-    "not dead",
-    "not ie <= 11",
-    "not op_mini all"
-  ],
+  "browserslist": [">0.2%", "not dead", "not ie <= 11", "not op_mini all"],
   "devDependencies": {
     "babel-eslint": "10.0.3",
     "babel-loader": "8.0.6",
diff --git a/editors/default/src/Default.js b/editors/default/src/Default.js
index 293753920728c2e58ea1f0fdd2afe284096f12e8..edfbd82f4abe194dfd5e7a35124910e401e71d6e 100644
--- a/editors/default/src/Default.js
+++ b/editors/default/src/Default.js
@@ -1,20 +1,9 @@
-import React, { Component } from "react";
-import { Wax, CreateSchema } from "wax-prosemirror-core";
-import { DefaultSchema } from "wax-prosemirror-schema";
+import React from "react";
+import { Wax } from "wax-prosemirror-core";
+import { DefaultLayout } from "wax-prosemirror-layouts";
 
-const plugins = [];
-const keys = {};
-
-const options = {
-  schema: new CreateSchema(DefaultSchema)
-};
-
-class Default extends Component {
-  render() {
-    return (
-      <Wax options={options} autoFocus placeholder="Type Something..." debug />
-    );
-  }
-}
+const Default = () => (
+  <Wax autoFocus placeholder="Type Something..." layout={DefaultLayout} debug />
+);
 
 export default Default;
diff --git a/editors/editoria/config-overrides.js b/editors/editoria/config-overrides.js
index 82c74c17dd0161dd58670ef1a2c591870a92e789..e2cf94482e8e7bc53cdb65bef9c758bbf04a1a3e 100644
--- a/editors/editoria/config-overrides.js
+++ b/editors/editoria/config-overrides.js
@@ -12,7 +12,11 @@ module.exports = function override(config, env) {
                 [require("@babel/preset-env"), { modules: false }],
                 require("@babel/preset-react")
               ],
-              plugins: [require("@babel/plugin-proposal-class-properties")]
+              plugins: [
+                ["@babel/plugin-proposal-decorators", { legacy: true }],
+                "babel-plugin-parameter-decorator",
+                ["@babel/plugin-proposal-class-properties", { loose: true }]
+              ]
             }
           },
           {
diff --git a/editors/editoria/jsconfig.json b/editors/editoria/jsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..504cd646e14906b4db8e943f9bfb10ab80162cee
--- /dev/null
+++ b/editors/editoria/jsconfig.json
@@ -0,0 +1,5 @@
+{
+  "compilerOptions": {
+    "experimentalDecorators": true
+  }
+}
diff --git a/editors/editoria/package.json b/editors/editoria/package.json
index 84d3efed8895446b76752176c05f02aa90af2be8..a6c89ffa3fb0c1828733693bd5fa50161ddf3464 100644
--- a/editors/editoria/package.json
+++ b/editors/editoria/package.json
@@ -12,8 +12,8 @@
     "wax-prosemirror-components": "^0.0.3",
     "wax-prosemirror-core": "^0.0.3",
     "wax-prosemirror-layouts": "^0.0.3",
-    "wax-prosemirror-schema": "^0.0.3",
-    "wax-prosemirror-themes": "^0.0.3"
+    "wax-prosemirror-themes": "^0.0.3",
+    "babel-plugin-parameter-decorator": "1.0.12"
   },
   "scripts": {
     "start": "react-app-rewired start",
@@ -24,12 +24,7 @@
   "eslintConfig": {
     "extends": "react-app"
   },
-  "browserslist": [
-    ">0.2%",
-    "not dead",
-    "not ie <= 11",
-    "not op_mini all"
-  ],
+  "browserslist": [">0.2%", "not dead", "not ie <= 11", "not op_mini all"],
   "devDependencies": {
     "babel-eslint": "10.0.3",
     "babel-loader": "8.0.6",
diff --git a/editors/editoria/src/EditorConfig.js b/editors/editoria/src/EditorConfig.js
deleted file mode 100644
index 1d0e2400863c6d7de810bd603f1e8574f7fa4bd9..0000000000000000000000000000000000000000
--- a/editors/editoria/src/EditorConfig.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import {
-  toggleMark,
-  wrapIn,
-  setBlockType,
-  exitCode,
-  joinUp,
-  joinDown,
-  lift,
-  selectParentNode
-} from "prosemirror-commands";
-
-import { goToNextCell } from "prosemirror-tables";
-
-import {
-  wrapInList,
-  splitListItem,
-  liftListItem,
-  sinkListItem
-} from "prosemirror-schema-list";
-
-import { emDash, ellipsis } from "prosemirror-inputrules";
-
-import invisibles, {
-  space,
-  hardBreak,
-  paragraph
-} from "@guardian/prosemirror-invisibles";
-
-import { CreateSchema, CreateShortCuts } from "wax-prosemirror-core";
-import { LinkToolTipPlugin, TrackChangePlugin } from "wax-prosemirror-plugins";
-import { tableNodes, columnResizing, tableEditing } from "prosemirror-tables";
-import { EditoriaSchema } from "wax-prosemirror-schema";
-
-const extraNodes = {
-  ...tableNodes({
-    tableGroup: "block",
-    cellContent: "block+"
-  })
-};
-
-// CreateSchema
-EditoriaSchema.nodes = { ...EditoriaSchema.nodes, ...extraNodes };
-const schema = new CreateSchema(EditoriaSchema);
-
-const shortCuts = {
-  "Mod-b": toggleMark(schema.marks.strong),
-  "Mod-i": toggleMark(schema.marks.em),
-  "Mod-u": toggleMark(schema.marks.underline),
-  "Mod-`": toggleMark(schema.marks.code),
-  "Ctrl->": wrapIn(schema.nodes.blockquote),
-  Enter: splitListItem(schema.nodes.list_item),
-  "Mod-[": liftListItem(schema.nodes.list_item),
-  "Mod-]": sinkListItem(schema.nodes.list_item),
-  "Alt-ArrowUp": joinUp,
-  "Alt-ArrowDown": joinDown,
-  "Mod-BracketLeft": lift,
-  Tab: goToNextCell(1),
-  "Shift-Tab": goToNextCell(-1),
-  "Shift-Ctrl-0": setBlockType(schema.nodes.paragraph),
-  "Shift-Ctrl-\\": setBlockType(schema.nodes.code_block),
-  "Shift-Ctrl-8": wrapInList(schema.nodes.bullet_list),
-  "Shift-Ctrl-9": wrapInList(schema.nodes.ordered_list),
-  "Shift-Ctrl-1": setBlockType(schema.nodes.heading, { level: 1 }),
-  "Shift-Ctrl-2": setBlockType(schema.nodes.heading, { level: 2 }),
-  "Shift-Ctrl-3": setBlockType(schema.nodes.heading, { level: 3 }),
-  "Shift-Ctrl-4": setBlockType(schema.nodes.heading, { level: 4 }),
-  "Shift-Ctrl-5": setBlockType(schema.nodes.heading, { level: 5 }),
-  "Shift-Ctrl-6": setBlockType(schema.nodes.heading, { level: 6 })
-};
-
-// Create shortCuts
-const keys = new CreateShortCuts({ schema, shortCuts });
-
-// Add Plugins
-const plugins = [
-  columnResizing(),
-  tableEditing(),
-  TrackChangePlugin({ options: {} }),
-  invisibles([hardBreak()])
-];
-
-// Add Rules
-const rules = [emDash, ellipsis];
-
-export { schema, keys, plugins, rules };
diff --git a/editors/editoria/src/Editoria.js b/editors/editoria/src/Editoria.js
index 44604454877091be1b7300ed8aee77feefcb9547..d1ec4b25547a00b440fc75dac04856a8c6e2a6ba 100644
--- a/editors/editoria/src/Editoria.js
+++ b/editors/editoria/src/Editoria.js
@@ -1,20 +1,12 @@
-import React, { Fragment, Component } from "react";
-import styled, { createGlobalStyle, ThemeProvider } from "styled-components";
-
-import { Wax } from "wax-prosemirror-core";
+import React, { Fragment } from "react";
+import styled, { createGlobalStyle } from "styled-components";
 import { EditoriaLayout } from "wax-prosemirror-layouts";
+import { Wax } from "wax-prosemirror-core";
 
-import { schema, keys, plugins, rules } from "./EditorConfig";
+import { config } from "./config";
 
 import text from "./text";
 
-const options = {
-  schema,
-  plugins,
-  keys,
-  rules
-};
-
 const GlobalStyle = createGlobalStyle`
   body {
     margin: 0;
@@ -48,26 +40,20 @@ const user = {
   username: "demo"
 };
 
-class Editoria extends Component {
-  render() {
-    return (
-      <Fragment>
-        <GlobalStyle />
-        <StyledWax
-          options={options}
-          autoFocus
-          placeholder="Type Something..."
-          fileUpload={file => renderImage(file)}
-          value=""
-          user={user}
-        >
-          {({ editor, view, ...props }) => (
-            <EditoriaLayout editor={editor} view={view} {...props} />
-          )}
-        </StyledWax>
-      </Fragment>
-    );
-  }
-}
+const Editoria = () => (
+  <Fragment>
+    <GlobalStyle />
+    <StyledWax
+      config={config}
+      autoFocus
+      placeholder="Type Something..."
+      fileUpload={file => renderImage(file)}
+      value="<h1> <span style='font-style:italic;'>test</span>hello <code> this is the code</code></p>"
+      layout={EditoriaLayout}
+      user={user}
+    />
+    <div id="editors" />
+  </Fragment>
+);
 
 export default Editoria;
diff --git a/editors/editoria/src/config/config.js b/editors/editoria/src/config/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..b31f1704dfe11f6fce63fff51731b7004f1c139a
--- /dev/null
+++ b/editors/editoria/src/config/config.js
@@ -0,0 +1,72 @@
+import { emDash, ellipsis } from "prosemirror-inputrules";
+import { columnResizing, tableEditing } from "prosemirror-tables";
+import {
+  AnnotationToolGroupService,
+  ImageService,
+  PlaceholderService,
+  InlineAnnotationsService,
+  LinkService,
+  ListsService,
+  ListToolGroupService,
+  TablesService,
+  TableToolGroupService,
+  BaseService,
+  BaseToolGroupService,
+  DisplayBlockLevelService,
+  DisplayToolGroupService,
+  ImageToolGroupService,
+  TextBlockLevelService,
+  TextToolGroupService,
+  TrackChangeService,
+  NoteService
+} from "wax-prosemirror-services";
+
+import invisibles, {
+  space,
+  hardBreak,
+  paragraph
+} from "@guardian/prosemirror-invisibles";
+
+export default {
+  MenuService: [
+    {
+      templateArea: "topBar",
+      toolGroups: ["Base", "Annotations", "Lists", "Images", "Tables"]
+    },
+    {
+      templateArea: "leftSideBar",
+      toolGroups: ["Display", "Text"]
+    }
+  ],
+
+  RulesService: [emDash, ellipsis],
+
+  ShortCutsService: {},
+
+  PmPlugins: [
+    columnResizing(),
+    tableEditing(),
+    // TrackChangePlugin({ options: {} }),
+    invisibles([hardBreak()])
+  ],
+  services: [
+    new ListToolGroupService(),
+    new PlaceholderService(),
+    new ImageService(),
+    new AnnotationToolGroupService(),
+    new InlineAnnotationsService(),
+    new LinkService(),
+    new ListsService(),
+    new TableToolGroupService(),
+    new TablesService(),
+    new BaseService(),
+    new BaseToolGroupService(),
+    new DisplayBlockLevelService(),
+    new DisplayToolGroupService(),
+    new ImageToolGroupService(),
+    new TextBlockLevelService(),
+    new TextToolGroupService(),
+    new TrackChangeService(),
+    new NoteService()
+  ]
+};
diff --git a/editors/editoria/src/config/index.js b/editors/editoria/src/config/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f7956eb2edcb829ef92c381826e48f0565cc9ab
--- /dev/null
+++ b/editors/editoria/src/config/index.js
@@ -0,0 +1 @@
+export { default as config } from "./config";
diff --git a/editors/editoria/src/index.js b/editors/editoria/src/index.js
index 0e2c96f0f74dab0d06a89ae7a46b098a57629470..dfa81ea6d6773b79a98806c481083c41507939ad 100644
--- a/editors/editoria/src/index.js
+++ b/editors/editoria/src/index.js
@@ -2,7 +2,6 @@ import React from "react";
 import ReactDOM from "react-dom";
 import Editoria from "./Editoria";
 import * as serviceWorker from "./serviceWorker";
-
 ReactDOM.render(<Editoria />, document.getElementById("root"));
 
 // If you want your app to work offline and load faster, you can change
diff --git a/editors/editoria/src/text.js b/editors/editoria/src/text.js
index e59a3f729ab02cba3646e74770977df5dc8a36d4..3c862a2cfe25d718a35c287fa712c95e4dd328d5 100644
--- a/editors/editoria/src/text.js
+++ b/editors/editoria/src/text.js
@@ -1,7 +1,5 @@
 // USE FOR TRACK TEST
-const text = `<ul><li><p class="paragraph">this is the li content</p></li>
-<li><p class="paragraph">And another</p></li></ul>
-<h1>this is a title</h1>
+const text = `
 <p class="paragraph" data-track="[{&quot;type&quot;:&quot;block_change&quot;,&quot;user&quot;:&quot;editor.user.id&quot;,&quot;username&quot;:&quot;editor.user.username&quot;,&quot;date&quot;:26069447,&quot;before&quot;:{&quot;type&quot;:&quot;author&quot;,&quot;attrs&quot;:{&quot;class&quot;:&quot;author&quot;}}}]">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
 <p class="author">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>`;
 
diff --git a/package.json b/package.json
index f58069cdae2c41a537cd5c44185c321617693ee6..915070bedeae09a5d315863fdc842efc0de9c9bd 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
   "dependencies": {},
   "devDependencies": {
     "@babel/plugin-proposal-class-properties": "^7.0.0",
+    "@babel/plugin-proposal-decorators": "^7.0.0",
     "@babel/preset-env": "^7.0.0",
     "@babel/preset-react": "^7.0.0",
     "css-loader": "^0.28.11",
@@ -47,6 +48,7 @@
     "wax-prosemirror-utilities",
     "wax-prosemirror-layouts",
     "wax-prosemirror-plugins",
+    "wax-prosemirror-services",
     "editors/*"
   ]
 }
diff --git a/wax-prosemirror-components/index.js b/wax-prosemirror-components/index.js
index c40a956b813ed0b8e7f67e17479b67c26f3b7bdb..38e547ec9f7b28aa08c150dd252ae21bf7264f56 100644
--- a/wax-prosemirror-components/index.js
+++ b/wax-prosemirror-components/index.js
@@ -1,3 +1,7 @@
-export { default as MainMenuBar } from "./src/mainMenuBar/MainMenuBar";
-export { default as SideMenuBar } from "./src/sideMenuBar/SideMenuBar";
 export { default as InfoArea } from "./src/components/infoArea/InfoArea";
+export { default as Overlay } from "./src/components/Overlay";
+export { default as Button } from "./src/components/Button";
+export { default as icons } from "./src/icons/icons";
+export { default as TableDropDown } from "./src/components/TableDropDown";
+export { default as ImageUpload } from "./src/components/ImageUpload";
+export { default as LeftMenuTitle } from "./src/components/LeftMenuTitle";
diff --git a/wax-prosemirror-components/src/components/Button.js b/wax-prosemirror-components/src/components/Button.js
index c8034b1b9beab6743b38c29ed499da833f2e60fc..ad3c1ec9a820d2ba1ee9a3060767ae10b2200092 100644
--- a/wax-prosemirror-components/src/components/Button.js
+++ b/wax-prosemirror-components/src/components/Button.js
@@ -15,20 +15,22 @@ const ButtonStyled = styled.button`
   }
 `;
 
-const Button = ({ view = {}, item }) => (
-  <ButtonStyled
-    type="button"
-    isActive={item.active && item.active(view.state)}
-    title={item.title}
-    disabled={item.enable && !item.enable(view.state)}
-    onMouseDown={e => {
-      e.preventDefault();
-      item.run(view.state, view.dispatch);
-    }}
-    select={item.select && item.select(view.state)}
-  >
-    {item.content}
-  </ButtonStyled>
-);
+const Button = ({ view = {}, item }) => {
+  return (
+    <ButtonStyled
+      type="button"
+      isActive={item.active && item.active(view.state)}
+      title={item.title}
+      disabled={item.enable && !item.enable(view.state)}
+      onMouseDown={e => {
+        e.preventDefault();
+        item.run(view.state, view.dispatch);
+      }}
+      select={item.select && item.select(view.state)}
+    >
+      {item.content}
+    </ButtonStyled>
+  );
+};
 
 export default Button;
diff --git a/wax-prosemirror-components/src/components/ImageUpload.js b/wax-prosemirror-components/src/components/ImageUpload.js
index 1fcc2272452ec26633e391eae8cacde141af1184..8c3995cb9049a9af6d767c1b65f3b61b03e70d37 100644
--- a/wax-prosemirror-components/src/components/ImageUpload.js
+++ b/wax-prosemirror-components/src/components/ImageUpload.js
@@ -13,7 +13,7 @@ const UploadImage = styled.div`
     display: none;
   }
 `;
-const ImageUpload = ({ item, view: { state }, handle, fileUpload }) => (
+const ImageUpload = ({ item, fileUpload }) => (
   <UploadImage>
     <label
       className="custom-file-upload"
diff --git a/wax-prosemirror-components/src/components/LeftMenuTitle.js b/wax-prosemirror-components/src/components/LeftMenuTitle.js
new file mode 100644
index 0000000000000000000000000000000000000000..15c4ac188abb43c6e70fe0942877d1b40a66b785
--- /dev/null
+++ b/wax-prosemirror-components/src/components/LeftMenuTitle.js
@@ -0,0 +1,26 @@
+import React from "react";
+import styled from "styled-components";
+
+const LeftMenuStyled = styled.div`
+  border-bottom: 1px solid #d9d9d9;
+  color: #979797;
+  font-family: "Fira Sans";
+  font-size: 15px;
+  font-weight: bold;
+  letter-spacing: 0.6px;
+  list-style: none;
+  line-height: 0;
+  margin: 5px 0;
+  display: block;
+  padding: 20px 0 10px;
+  margin-left: 10px;
+  text-align: left;
+  text-transform: uppercase;
+  width: 51%;
+`;
+
+const LeftMenuTitle = ({ title }) => {
+  return <LeftMenuStyled>{title}</LeftMenuStyled>;
+};
+
+export default LeftMenuTitle;
diff --git a/wax-prosemirror-components/src/components/Overlay.js b/wax-prosemirror-components/src/components/Overlay.js
new file mode 100644
index 0000000000000000000000000000000000000000..c695389e0717102571dfab7461d8d0ed93b6dabb
--- /dev/null
+++ b/wax-prosemirror-components/src/components/Overlay.js
@@ -0,0 +1,13 @@
+import React from "react";
+import styled from "styled-components";
+const OverlayContainer = styled.div`
+  position: ${props => props.position.position};
+  left: ${props => `${props.position.left}px`};
+  top: ${props => `${props.position.top}px`};
+`;
+
+const Overlay = props => (
+  <OverlayContainer {...props}>{props.children}</OverlayContainer>
+);
+
+export default Overlay;
diff --git a/wax-prosemirror-components/src/components/TableDropDown.js b/wax-prosemirror-components/src/components/TableDropDown.js
index 851a93223a7d7fd432a17f4be65fa9c154221240..4115ece997d77381fe6d9b910f6ed40838765b51 100644
--- a/wax-prosemirror-components/src/components/TableDropDown.js
+++ b/wax-prosemirror-components/src/components/TableDropDown.js
@@ -13,8 +13,12 @@ const DropdownStyled = styled(Dropdown)`
     border: none;
   }
   .Dropdown-arrow {
+    right: 25px;
     top: 21px;
   }
+  .Dropdown-menu {
+    width: 120%;
+  }
 `;
 
 const dropDownOptions = [
diff --git a/wax-prosemirror-components/src/components/infoArea/InfoArea.js b/wax-prosemirror-components/src/components/infoArea/InfoArea.js
index 1abbefdfa4d2fc492fd17d576aaec5e3df7821a2..ae6e088a0436acedf57143d30c5c9929ca18edeb 100644
--- a/wax-prosemirror-components/src/components/infoArea/InfoArea.js
+++ b/wax-prosemirror-components/src/components/infoArea/InfoArea.js
@@ -2,12 +2,12 @@ import React from "react";
 import styled from "styled-components";
 
 const InfoAreaContainer = styled.div`
-  height: ${props => (props.height ? props.height : "30px")};
+  ${"" /* height: ${props => (props.height ? props.height : "30px")};
   position: fixed;
   bottom: 0;
   z-index: 9999;
   background: #efefef;
-  width: 100%;
+  width: 100%;*/};
 `;
 
 const InfoArea = () => <InfoAreaContainer />;
diff --git a/wax-prosemirror-components/src/helpers.js b/wax-prosemirror-components/src/helpers.js
deleted file mode 100644
index bdb81d6b452a7fd726ed57c50bd88b7c3f122f85..0000000000000000000000000000000000000000
--- a/wax-prosemirror-components/src/helpers.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const filtered = (menu, menuItems) =>
-  Object.keys(menu)
-    .filter(key => menuItems.includes(key))
-    .reduce((obj, key) => {
-      obj[key] = menu[key];
-      return obj;
-    }, {});
-
-const setMenuItems = (allMenuItems, menuItems) => {
-  if (menuItems.length === 0) return allMenuItems;
-  return filtered(allMenuItems, menuItems);
-};
-
-export { setMenuItems };
diff --git a/wax-prosemirror-components/src/mainMenuBar/MainMenuBar.js b/wax-prosemirror-components/src/mainMenuBar/MainMenuBar.js
deleted file mode 100644
index 088cccf579e45995f80de4d2beae4ccbcdf59201..0000000000000000000000000000000000000000
--- a/wax-prosemirror-components/src/mainMenuBar/MainMenuBar.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-import { map } from "lodash";
-import MainMenuBarItems from "./MainMenuBarItems";
-import { setMenuItems } from "../helpers";
-
-const MainMenuContainer = styled.div`
-  background: #fff;
-  height: 52px;
-  line-height: 32px;
-  position: relative;
-  user-select: none;
-`;
-const MainMenuInner = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-direction: column;
-  left: 0;
-  position: absolute;
-  right: 0;
-  top: 0;
-  background: transparent;
-  z-index: 9999;
-`;
-const MainMenu = styled.div`
-  background: #fff;
-  padding: 2px 2px 2px 0;
-  position: relative;
-  background: transparent;
-`;
-
-const MainMenuBar = ({ menuItems = [], view, className, fileUpload }) => (
-  <MainMenuContainer>
-    <MainMenuInner>
-      <MainMenu>
-        {map(setMenuItems(MainMenuBarItems, menuItems), item =>
-          item.menu({ view, item, fileUpload })
-        )}
-      </MainMenu>
-    </MainMenuInner>
-  </MainMenuContainer>
-);
-
-export default MainMenuBar;
diff --git a/wax-prosemirror-components/src/mainMenuBar/MainMenuBarItems.js b/wax-prosemirror-components/src/mainMenuBar/MainMenuBarItems.js
deleted file mode 100644
index f9c9fc79fb22bedaffe104851ca8ad308dc99b4c..0000000000000000000000000000000000000000
--- a/wax-prosemirror-components/src/mainMenuBar/MainMenuBarItems.js
+++ /dev/null
@@ -1,260 +0,0 @@
-import React from "react";
-import { v4 as uuid } from "uuid";
-import {
-  joinUp,
-  lift,
-  setBlockType,
-  toggleMark,
-  wrapIn,
-  selectParentNode
-} from "prosemirror-commands";
-
-import { addColumnBefore } from "prosemirror-tables";
-
-import { redo, undo } from "prosemirror-history";
-import { wrapInList } from "prosemirror-schema-list";
-
-import icons from "../icons/icons";
-//Components
-import Button from "../components/Button";
-import TableDropDown from "../components/TableDropDown";
-import ImageUpload from "../components/ImageUpload";
-import HeadingsDropDown from "../components/HeadingsDropDown";
-
-import {
-  markActive,
-  blockActive,
-  canInsert,
-  promptForURL,
-  createTable
-} from "./MainMenuCommands";
-
-export default {
-  undo: {
-    title: "Undo last change",
-    content: icons.undo,
-    enable: undo,
-    run: undo,
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  redo: {
-    title: "Redo last undone change",
-    content: icons.redo,
-    enable: redo,
-    run: redo,
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  em: {
-    title: "Toggle emphasis",
-    content: icons.em,
-    active: state => {
-      return markActive(state.config.schema.marks.em)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.em)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  strong: {
-    title: "Toggle strong",
-    content: icons.strong,
-    active: state => {
-      return markActive(state.config.schema.marks.strong)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.strong)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  code: {
-    title: "Toggle code",
-    content: icons.code,
-    active: state => {
-      return markActive(state.config.schema.marks.code)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.code)(state, dispatch);
-    },
-
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  small_caps: {
-    title: "Toggle Small Caps",
-    content: icons.small_caps,
-    active: state => {
-      return markActive(state.config.schema.marks.small_caps)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.small_caps)(state, dispatch);
-    },
-
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  subscript: {
-    title: "Toggle subscript",
-    content: icons.subscript,
-    active: state => {
-      return markActive(state.config.schema.marks.subscript)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.subscript)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  superscript: {
-    title: "Toggle superscript",
-    content: icons.superscript,
-    active: state => {
-      return markActive(state.config.schema.marks.superscript)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.superscript)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  underline: {
-    title: "Toggle underline",
-    content: icons.underline,
-    active: state => {
-      return markActive(state.config.schema.marks.underline)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.underline)(state, dispatch);
-    },
-
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  strikethrough: {
-    title: "Toggle strikethrough",
-    content: icons.strikethrough,
-    active: state => {
-      return markActive(state.config.schema.marks.strikethrough)(state);
-    },
-    run(state, dispatch) {
-      toggleMark(state.config.schema.marks.strikethrough)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  link: {
-    title: "Add or remove link",
-    content: icons.link,
-    active: state => {
-      return markActive(state.config.schema.marks.link)(state);
-    },
-    enable: state => !state.selection.empty,
-    run(state, dispatch) {
-      if (markActive(state.config.schema.marks.link)(state)) {
-        toggleMark(state.config.schema.marks.link)(state, dispatch);
-        return true;
-      }
-
-      const href = promptForURL();
-      if (!href) return false;
-
-      toggleMark(state.config.schema.marks.link, { href })(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  blockquote: {
-    title: "Wrap in block quote",
-    content: icons.blockquote,
-    active: state => {
-      return blockActive(state.config.schema.nodes.blockquote)(state);
-    },
-    enable: state => {
-      return wrapIn(state.config.schema.nodes.blockquote)(state);
-    },
-    run(state, dispatch) {
-      wrapIn(state.config.schema.nodes.blockquote)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  bullet_list: {
-    title: "Wrap in bullet list",
-    content: icons.bullet_list,
-    active: state => {
-      return blockActive(state.config.schema.nodes.bullet_list)(state);
-    },
-    enable: state => {
-      return wrapInList(state.config.schema.nodes.bullet_list)(state);
-    },
-    run(state, dispatch) {
-      wrapInList(state.config.schema.nodes.bullet_list)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  ordered_list: {
-    title: "Wrap in ordered list",
-    content: icons.ordered_list,
-    active: state => {
-      return blockActive(state.config.schema.nodes.ordered_list)(state);
-    },
-    enable: state => {
-      return wrapInList(state.config.schema.nodes.ordered_list)(state);
-    },
-    run(state, dispatch) {
-      wrapInList(state.config.schema.nodes.ordered_list)(state, dispatch);
-    },
-
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  lift: {
-    title: "Lift out of enclosing block",
-    content: icons.lift,
-    enable: lift,
-    run: lift,
-    select: state => lift(state),
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  join_up: {
-    title: "Join with above block",
-    content: icons.join_up,
-    select: state => joinUp(state),
-    enable: joinUp,
-    run: joinUp,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  image: {
-    title: "Insert image",
-    content: icons.image,
-    enable: state => {
-      return canInsert(state.config.schema.nodes.image)(state);
-    },
-    select: state => true,
-    run: option => true,
-    menu: props => <ImageUpload key={uuid()} {...props} />
-  },
-  table: {
-    title: "Insert table",
-    content: icons.table,
-    enable: state => {
-      return canInsert(state.config.schema.nodes.table)(state);
-    },
-    run: (state, dispatch) => {
-      return createTable(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  tableDropDownOptions: {
-    content: "table",
-    run: option => true,
-    title: "Select Options",
-    select: state => addColumnBefore(state),
-    menu: props => <TableDropDown key={uuid()} {...props} />
-  }
-};
diff --git a/wax-prosemirror-components/src/sideMenuBar/SideMenuBar.js b/wax-prosemirror-components/src/sideMenuBar/SideMenuBar.js
deleted file mode 100644
index 4b2abd2ce9defc5cd4807fc41fc01d27a5ca1a4c..0000000000000000000000000000000000000000
--- a/wax-prosemirror-components/src/sideMenuBar/SideMenuBar.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-import { map } from "lodash";
-import SideMenuItems from "./SideMenuItems";
-import { setMenuItems } from "../helpers";
-
-const SideMenuContainer = styled.div`
-  display: flex;
-  width: 12%;
-  height: 98%;
-`;
-
-const SideMenuInner = styled.div`
-  display: flex;
-  width: 100%;
-`;
-
-const SideMenu = styled.div`
-  flex: 1;
-  display: flex;
-  flex-direction: column;
-  justify-content: flex-start;
-  margin-top: 15px;
-  button {
-    display: flex;
-    flex-direction: column;
-    font-family: ${props => props.theme.fontInterface};
-    margin-left: 5%;
-    width: 90%;
-  }
-`;
-
-const SideMenuBar = ({ menuItems = [], view, className }) => (
-  <SideMenuContainer>
-    <SideMenuInner>
-      <SideMenu>
-        {map(setMenuItems(SideMenuItems, menuItems), item =>
-          item.menu({ view, item })
-        )}
-      </SideMenu>
-    </SideMenuInner>
-  </SideMenuContainer>
-);
-
-export default SideMenuBar;
diff --git a/wax-prosemirror-components/src/sideMenuBar/SideMenuCommands.js b/wax-prosemirror-components/src/sideMenuBar/SideMenuCommands.js
deleted file mode 100644
index b9620b65822dcfcefe5e41c41de9e80e136bf852..0000000000000000000000000000000000000000
--- a/wax-prosemirror-components/src/sideMenuBar/SideMenuCommands.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const blockActive = (type, attrs = {}) => state => {
-  const { $from, to, node } = state.selection;
-
-  if (node) {
-    return node.hasMarkup(type, attrs);
-  }
-  return to <= $from.end() && $from.parent.hasMarkup(type, attrs);
-};
-
-export { blockActive };
diff --git a/wax-prosemirror-components/src/sideMenuBar/SideMenuItems.js b/wax-prosemirror-components/src/sideMenuBar/SideMenuItems.js
deleted file mode 100644
index efef95626e7910e9f4c8343bfcb9647f1d9fbb9c..0000000000000000000000000000000000000000
--- a/wax-prosemirror-components/src/sideMenuBar/SideMenuItems.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import React from "react";
-import { v4 as uuid } from "uuid";
-import { setBlockType } from "prosemirror-commands";
-
-import Button from "../components/Button";
-import { blockActive } from "./SideMenuItems";
-export default {
-  title: {
-    title: "Change to Title",
-    content: "Title",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.title)(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.title)(state, dispatch);
-    },
-
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  subtitle: {
-    title: "Change to Subtilte",
-    content: "Subtilte",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.subtitle)(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.subtitle)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  author: {
-    title: "Change to Author",
-    content: "Author",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.author)(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.author)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  epigraphPoetry: {
-    title: "Change to Epigraph Poetry",
-    content: "Epigraph Poetry",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.epigraphPoetry)(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.epigraphPoetry)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  epigraphProse: {
-    title: "Change to Epigraph Prose",
-    content: "Epigraph Prose",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.epigraphProse)(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.epigraphProse)(state, dispatch);
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  plain: {
-    title: "Change to General Text",
-    content: "General Text",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.paragraph)(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.paragraph)(state, dispatch);
-    },
-
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  heading1: {
-    title: "Change to heading level 1",
-    content: "Heading 1",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.heading, {
-        level: 1,
-        track: []
-      })(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.heading, { level: 1 })(
-        state,
-        dispatch
-      );
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  heading2: {
-    title: "Change to heading level 2",
-    content: "Heading 2",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.heading, {
-        level: 2,
-        track: []
-      })(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.heading, { level: 2 })(
-        state,
-        dispatch
-      );
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  },
-  heading3: {
-    title: "Change to heading level 3",
-    content: "Heading 3",
-    group: "",
-    enable: state => {
-      return setBlockType(state.config.schema.nodes.heading, {
-        level: 3,
-        track: []
-      })(state);
-    },
-    run(state, dispatch) {
-      setBlockType(state.config.schema.nodes.heading, { level: 3 })(
-        state,
-        dispatch
-      );
-    },
-    select: state => true,
-    menu: props => <Button key={uuid()} {...props} />
-  }
-};
diff --git a/wax-prosemirror-core/.directory b/wax-prosemirror-core/.directory
deleted file mode 100644
index cac92e2624c87ddd8b448be49dc9e6f87a6c590d..0000000000000000000000000000000000000000
--- a/wax-prosemirror-core/.directory
+++ /dev/null
@@ -1,6 +0,0 @@
-[Dolphin]
-Timestamp=2019,4,9,20,32,38
-Version=3
-
-[Settings]
-HiddenFilesShown=true
diff --git a/wax-prosemirror-core/index.js b/wax-prosemirror-core/index.js
index 6f7daa4c928567033c1ef6e58e32b0aac3f64974..3b761a2640914a896c09c25399aeefae9447f7bb 100644
--- a/wax-prosemirror-core/index.js
+++ b/wax-prosemirror-core/index.js
@@ -1,5 +1,4 @@
 export { default as Wax } from "./src/Wax";
-export { default as CreateSchema } from "./src/config/classes/CreateSchema";
-export {
-  default as CreateShortCuts
-} from "./src/config/classes/CreateShortCuts";
+export { default as Service } from "./src/services/Service";
+export { default as WaxContext } from "./src/ioc-react";
+export { default as componentPlugin } from "./src/services/LayoutService/components/componentPlugin";
diff --git a/wax-prosemirror-core/jsconfig.json b/wax-prosemirror-core/jsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..504cd646e14906b4db8e943f9bfb10ab80162cee
--- /dev/null
+++ b/wax-prosemirror-core/jsconfig.json
@@ -0,0 +1,5 @@
+{
+  "compilerOptions": {
+    "experimentalDecorators": true
+  }
+}
diff --git a/wax-prosemirror-core/package-lock.json b/wax-prosemirror-core/package-lock.json
deleted file mode 100644
index 1d17f687bca47973d5f2200831d1f5b79ffd25ae..0000000000000000000000000000000000000000
--- a/wax-prosemirror-core/package-lock.json
+++ /dev/null
@@ -1,823 +0,0 @@
-{
-  "name": "wax-prosemirror-core",
-  "version": "0.0.3",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "@babel/helper-module-imports": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz",
-      "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "7.4.0"
-      }
-    },
-    "@babel/runtime": {
-      "version": "7.4.3",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz",
-      "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==",
-      "dev": true,
-      "requires": {
-        "regenerator-runtime": "0.13.2"
-      }
-    },
-    "@babel/types": {
-      "version": "7.4.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz",
-      "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==",
-      "dev": true,
-      "requires": {
-        "esutils": "2.0.2",
-        "lodash": "4.17.11",
-        "to-fast-properties": "2.0.0"
-      },
-      "dependencies": {
-        "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
-          "dev": true
-        }
-      }
-    },
-    "@emotion/babel-utils": {
-      "version": "0.6.10",
-      "resolved": "https://registry.npmjs.org/@emotion/babel-utils/-/babel-utils-0.6.10.tgz",
-      "integrity": "sha512-/fnkM/LTEp3jKe++T0KyTszVGWNKPNOUJfjNKLO17BzQ6QPxgbg3whayom1Qr2oLFH3V92tDymU+dT5q676uow==",
-      "dev": true,
-      "requires": {
-        "@emotion/hash": "0.6.6",
-        "@emotion/memoize": "0.6.6",
-        "@emotion/serialize": "0.9.1",
-        "convert-source-map": "1.6.0",
-        "find-root": "1.1.0",
-        "source-map": "0.7.3"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
-        }
-      }
-    },
-    "@emotion/hash": {
-      "version": "0.6.6",
-      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.6.6.tgz",
-      "integrity": "sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ==",
-      "dev": true
-    },
-    "@emotion/is-prop-valid": {
-      "version": "0.6.8",
-      "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.6.8.tgz",
-      "integrity": "sha512-IMSL7ekYhmFlILXcouA6ket3vV7u9BqStlXzbKOF9HBtpUPMMlHU+bBxrLOa2NvleVwNIxeq/zL8LafLbeUXcA==",
-      "dev": true,
-      "requires": {
-        "@emotion/memoize": "0.6.6"
-      }
-    },
-    "@emotion/memoize": {
-      "version": "0.6.6",
-      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz",
-      "integrity": "sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ==",
-      "dev": true
-    },
-    "@emotion/serialize": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.9.1.tgz",
-      "integrity": "sha512-zTuAFtyPvCctHBEL8KZ5lJuwBanGSutFEncqLn/m9T1a6a93smBStK+bZzcNPgj4QS8Rkw9VTwJGhRIUVO8zsQ==",
-      "dev": true,
-      "requires": {
-        "@emotion/hash": "0.6.6",
-        "@emotion/memoize": "0.6.6",
-        "@emotion/unitless": "0.6.7",
-        "@emotion/utils": "0.8.2"
-      }
-    },
-    "@emotion/stylis": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.7.1.tgz",
-      "integrity": "sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ==",
-      "dev": true
-    },
-    "@emotion/unitless": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.6.7.tgz",
-      "integrity": "sha512-Arj1hncvEVqQ2p7Ega08uHLr1JuRYBuO5cIvcA+WWEQ5+VmkOE3ZXzl04NbQxeQpWX78G7u6MqxKuNX3wvYZxg==",
-      "dev": true
-    },
-    "@emotion/utils": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz",
-      "integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw==",
-      "dev": true
-    },
-    "abbrev": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
-      "dev": true
-    },
-    "ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
-      "requires": {
-        "color-convert": "1.9.3"
-      }
-    },
-    "argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dev": true,
-      "requires": {
-        "sprintf-js": "1.0.3"
-      }
-    },
-    "babel-plugin-emotion": {
-      "version": "9.2.11",
-      "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz",
-      "integrity": "sha512-dgCImifnOPPSeXod2znAmgc64NhaaOjGEHROR/M+lmStb3841yK1sgaDYAYMnlvWNz8GnpwIPN0VmNpbWYZ+VQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-imports": "7.0.0",
-        "@emotion/babel-utils": "0.6.10",
-        "@emotion/hash": "0.6.6",
-        "@emotion/memoize": "0.6.6",
-        "@emotion/stylis": "0.7.1",
-        "babel-plugin-macros": "2.5.1",
-        "babel-plugin-syntax-jsx": "6.18.0",
-        "convert-source-map": "1.6.0",
-        "find-root": "1.1.0",
-        "mkdirp": "0.5.1",
-        "source-map": "0.5.7",
-        "touch": "2.0.2"
-      }
-    },
-    "babel-plugin-macros": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz",
-      "integrity": "sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==",
-      "dev": true,
-      "requires": {
-        "@babel/runtime": "7.4.3",
-        "cosmiconfig": "5.2.0",
-        "resolve": "1.10.0"
-      }
-    },
-    "babel-plugin-syntax-jsx": {
-      "version": "6.18.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
-      "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=",
-      "dev": true
-    },
-    "babel-runtime": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
-      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
-      "dev": true,
-      "requires": {
-        "core-js": "2.6.5",
-        "regenerator-runtime": "0.11.1"
-      },
-      "dependencies": {
-        "regenerator-runtime": {
-          "version": "0.11.1",
-          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
-          "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
-          "dev": true
-        }
-      }
-    },
-    "base16": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
-      "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=",
-      "dev": true
-    },
-    "buffer-from": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
-      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
-      "dev": true
-    },
-    "caller-callsite": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
-      "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
-      "dev": true,
-      "requires": {
-        "callsites": "2.0.0"
-      }
-    },
-    "caller-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
-      "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
-      "dev": true,
-      "requires": {
-        "caller-callsite": "2.0.0"
-      }
-    },
-    "callsites": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
-      "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
-      "dev": true
-    },
-    "chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "3.2.1",
-        "escape-string-regexp": "1.0.5",
-        "supports-color": "5.5.0"
-      }
-    },
-    "color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
-      "requires": {
-        "color-name": "1.1.3"
-      }
-    },
-    "color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
-    },
-    "concat-stream": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "1.1.1",
-        "inherits": "2.0.3",
-        "readable-stream": "2.3.6",
-        "typedarray": "0.0.6"
-      }
-    },
-    "convert-source-map": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
-      "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "5.1.2"
-      }
-    },
-    "core-js": {
-      "version": "2.6.5",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
-      "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==",
-      "dev": true
-    },
-    "core-util-is": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
-      "dev": true
-    },
-    "cosmiconfig": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz",
-      "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==",
-      "dev": true,
-      "requires": {
-        "import-fresh": "2.0.0",
-        "is-directory": "0.3.1",
-        "js-yaml": "3.13.1",
-        "parse-json": "4.0.0"
-      }
-    },
-    "create-emotion": {
-      "version": "9.2.12",
-      "resolved": "https://registry.npmjs.org/create-emotion/-/create-emotion-9.2.12.tgz",
-      "integrity": "sha512-P57uOF9NL2y98Xrbl2OuiDQUZ30GVmASsv5fbsjF4Hlraip2kyAvMm+2PoYUvFFw03Fhgtxk3RqZSm2/qHL9hA==",
-      "dev": true,
-      "requires": {
-        "@emotion/hash": "0.6.6",
-        "@emotion/memoize": "0.6.6",
-        "@emotion/stylis": "0.7.1",
-        "@emotion/unitless": "0.6.7",
-        "csstype": "2.6.3",
-        "stylis": "3.5.4",
-        "stylis-rule-sheet": "0.0.10"
-      }
-    },
-    "create-emotion-styled": {
-      "version": "9.2.8",
-      "resolved": "https://registry.npmjs.org/create-emotion-styled/-/create-emotion-styled-9.2.8.tgz",
-      "integrity": "sha512-2LrNM5MREWzI5hZK+LyiBHglwE18WE3AEbBQgpHQ1+zmyLSm/dJsUZBeFAwuIMb+TjNZP0KsMZlV776ufOtFdg==",
-      "dev": true,
-      "requires": {
-        "@emotion/is-prop-valid": "0.6.8"
-      }
-    },
-    "create-react-context": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.1.6.tgz",
-      "integrity": "sha512-eCnYYEUEc5i32LHwpE/W7NlddOB9oHwsPaWtWzYtflNkkwa3IfindIcoXdVWs12zCbwaMCavKNu84EXogVIWHw==",
-      "dev": true
-    },
-    "csstype": {
-      "version": "2.6.3",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.3.tgz",
-      "integrity": "sha512-rINUZXOkcBmoHWEyu7JdHu5JMzkGRoMX4ov9830WNgxf5UYxcBUO0QTKAqeJ5EZfSdlrcJYkC8WwfVW7JYi4yg==",
-      "dev": true
-    },
-    "diff-match-patch": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz",
-      "integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==",
-      "dev": true
-    },
-    "emotion": {
-      "version": "9.2.12",
-      "resolved": "https://registry.npmjs.org/emotion/-/emotion-9.2.12.tgz",
-      "integrity": "sha512-hcx7jppaI8VoXxIWEhxpDW7I+B4kq9RNzQLmsrF6LY8BGKqe2N+gFAQr0EfuFucFlPs2A9HM4+xNj4NeqEWIOQ==",
-      "dev": true,
-      "requires": {
-        "babel-plugin-emotion": "9.2.11",
-        "create-emotion": "9.2.12"
-      }
-    },
-    "error-ex": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-      "dev": true,
-      "requires": {
-        "is-arrayish": "0.2.1"
-      }
-    },
-    "es6-object-assign": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
-      "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=",
-      "dev": true
-    },
-    "escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
-    },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
-    },
-    "esutils": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
-      "dev": true
-    },
-    "find-root": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
-      "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
-      "dev": true
-    },
-    "has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
-    },
-    "html": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/html/-/html-1.0.0.tgz",
-      "integrity": "sha1-pUT6nqVJK/s6LMqCEKEL57WvH2E=",
-      "dev": true,
-      "requires": {
-        "concat-stream": "1.6.2"
-      }
-    },
-    "ie-array-find-polyfill": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/ie-array-find-polyfill/-/ie-array-find-polyfill-1.1.0.tgz",
-      "integrity": "sha1-UHjlM/Amgx2iK9dHZRPZRg1loUI=",
-      "dev": true
-    },
-    "import-fresh": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
-      "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
-      "dev": true,
-      "requires": {
-        "caller-path": "2.0.0",
-        "resolve-from": "3.0.0"
-      }
-    },
-    "inherits": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-      "dev": true
-    },
-    "is-arrayish": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
-      "dev": true
-    },
-    "is-directory": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
-      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
-      "dev": true
-    },
-    "isarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-      "dev": true
-    },
-    "js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
-    },
-    "js-yaml": {
-      "version": "3.13.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
-      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
-      "dev": true,
-      "requires": {
-        "argparse": "1.0.10",
-        "esprima": "4.0.1"
-      }
-    },
-    "json-parse-better-errors": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
-      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
-      "dev": true
-    },
-    "jsondiffpatch": {
-      "version": "0.3.11",
-      "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.3.11.tgz",
-      "integrity": "sha512-Xi3Iygdt/BGhml6bdUFhgDki1TgOsp3hG3iiH3KtzP+CahtGcdPfKRLlnZbSw+3b1umZkhmKrqXUgUcKenyhtA==",
-      "dev": true,
-      "requires": {
-        "chalk": "2.4.2",
-        "diff-match-patch": "1.0.4"
-      }
-    },
-    "lodash._getnative": {
-      "version": "3.9.1",
-      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
-      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
-      "dev": true
-    },
-    "lodash.curry": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
-      "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=",
-      "dev": true
-    },
-    "lodash.debounce": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz",
-      "integrity": "sha1-gSIRw3ipTMKdWqTjNGzwv846ffU=",
-      "dev": true,
-      "requires": {
-        "lodash._getnative": "3.9.1"
-      }
-    },
-    "lodash.flow": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
-      "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=",
-      "dev": true
-    },
-    "loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "dev": true,
-      "requires": {
-        "js-tokens": "4.0.0"
-      }
-    },
-    "minimist": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-      "dev": true
-    },
-    "mkdirp": {
-      "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
-      "dev": true,
-      "requires": {
-        "minimist": "0.0.8"
-      }
-    },
-    "nopt": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
-      "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
-      "dev": true,
-      "requires": {
-        "abbrev": "1.1.1"
-      }
-    },
-    "object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
-    },
-    "orderedmap": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.0.0.tgz",
-      "integrity": "sha1-2Q/Cuh7QhRkJB9YB3sbmpT+NQbo=",
-      "dev": true
-    },
-    "parse-json": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-      "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
-      "dev": true,
-      "requires": {
-        "error-ex": "1.3.2",
-        "json-parse-better-errors": "1.0.2"
-      }
-    },
-    "path-parse": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
-      "dev": true
-    },
-    "process-nextick-args": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
-      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
-      "dev": true
-    },
-    "prop-types": {
-      "version": "15.7.2",
-      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
-      "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
-      "dev": true,
-      "requires": {
-        "loose-envify": "1.4.0",
-        "object-assign": "4.1.1",
-        "react-is": "16.8.6"
-      }
-    },
-    "prosemirror-dev-tools": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/prosemirror-dev-tools/-/prosemirror-dev-tools-2.1.1.tgz",
-      "integrity": "sha512-d9MG4PF82meg5Ru64ox6WCKPkQNsiZEaG5xR5a+l88RJ0VRButMZq5JzPh28vUlTBq+TXnpdTJRlPQIgTOtpqg==",
-      "dev": true,
-      "requires": {
-        "emotion": "9.2.12",
-        "es6-object-assign": "1.1.0",
-        "html": "1.0.0",
-        "ie-array-find-polyfill": "1.1.0",
-        "jsondiffpatch": "0.3.11",
-        "prop-types": "15.7.2",
-        "prosemirror-model": "1.7.0",
-        "prosemirror-state": "1.2.2",
-        "react-dock": "0.2.4",
-        "react-emotion": "9.2.12",
-        "react-json-tree": "0.11.2",
-        "unstated": "2.1.1"
-      },
-      "dependencies": {
-        "prosemirror-model": {
-          "version": "1.7.0",
-          "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.7.0.tgz",
-          "integrity": "sha512-/6ul6guiqyAl5I+0qbnL7SlmuX0DEfYqjvzeLUVEnb7nwF/vmKZuWqbjEG2tqi/9SSudvd3UxQTBDHvxy9hQwA==",
-          "dev": true,
-          "requires": {
-            "orderedmap": "1.0.0"
-          }
-        },
-        "prosemirror-state": {
-          "version": "1.2.2",
-          "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.2.2.tgz",
-          "integrity": "sha512-j8aC/kf9BJSCQau485I/9pj39XQoce+TqH5xzekT7WWFARTsRYFLJtiXBcCKakv1VSeev+sC3bJP0pLfz7Ft8g==",
-          "dev": true,
-          "requires": {
-            "prosemirror-model": "1.7.0",
-            "prosemirror-transform": "1.1.3"
-          }
-        }
-      }
-    },
-    "prosemirror-transform": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.1.3.tgz",
-      "integrity": "sha512-1O6Di5lOL1mp4nuCnQNkHY7l2roIW5y8RH4ZG3hMYmkmDEWzTaFFnxxAAHsE5ipGLBSRcTlP7SsDhYBIdSuLpQ==",
-      "dev": true,
-      "requires": {
-        "prosemirror-model": "1.7.0"
-      },
-      "dependencies": {
-        "prosemirror-model": {
-          "version": "1.7.0",
-          "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.7.0.tgz",
-          "integrity": "sha512-/6ul6guiqyAl5I+0qbnL7SlmuX0DEfYqjvzeLUVEnb7nwF/vmKZuWqbjEG2tqi/9SSudvd3UxQTBDHvxy9hQwA==",
-          "dev": true,
-          "requires": {
-            "orderedmap": "1.0.0"
-          }
-        }
-      }
-    },
-    "pure-color": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
-      "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=",
-      "dev": true
-    },
-    "react-base16-styling": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz",
-      "integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=",
-      "dev": true,
-      "requires": {
-        "base16": "1.0.0",
-        "lodash.curry": "4.1.1",
-        "lodash.flow": "3.5.0",
-        "pure-color": "1.3.0"
-      }
-    },
-    "react-dock": {
-      "version": "0.2.4",
-      "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.2.4.tgz",
-      "integrity": "sha1-5yfcdVCztzEWY13LnA4E0Lev4Xw=",
-      "dev": true,
-      "requires": {
-        "lodash.debounce": "3.1.1",
-        "prop-types": "15.7.2"
-      }
-    },
-    "react-emotion": {
-      "version": "9.2.12",
-      "resolved": "https://registry.npmjs.org/react-emotion/-/react-emotion-9.2.12.tgz",
-      "integrity": "sha512-qt7XbxnEKX5sZ73rERJ92JMbEOoyOwG3BuCRFRkXrsJhEe+rFBRTljRw7yOLHZUCQC4GBObZhjXIduQ8S0ZpYw==",
-      "dev": true,
-      "requires": {
-        "babel-plugin-emotion": "9.2.11",
-        "create-emotion-styled": "9.2.8"
-      }
-    },
-    "react-is": {
-      "version": "16.8.6",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
-      "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==",
-      "dev": true
-    },
-    "react-json-tree": {
-      "version": "0.11.2",
-      "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.11.2.tgz",
-      "integrity": "sha512-aYhUPj1y5jR3ZQ+G3N7aL8FbTyO03iLwnVvvEikLcNFqNTyabdljo9xDftZndUBFyyyL0aK3qGO9+8EilILHUw==",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "6.26.0",
-        "prop-types": "15.7.2",
-        "react-base16-styling": "0.5.3"
-      }
-    },
-    "readable-stream": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-      "dev": true,
-      "requires": {
-        "core-util-is": "1.0.2",
-        "inherits": "2.0.3",
-        "isarray": "1.0.0",
-        "process-nextick-args": "2.0.0",
-        "safe-buffer": "5.1.2",
-        "string_decoder": "1.1.1",
-        "util-deprecate": "1.0.2"
-      }
-    },
-    "regenerator-runtime": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
-      "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==",
-      "dev": true
-    },
-    "resolve": {
-      "version": "1.10.0",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
-      "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
-      "dev": true,
-      "requires": {
-        "path-parse": "1.0.6"
-      }
-    },
-    "resolve-from": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
-      "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
-      "dev": true
-    },
-    "safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "dev": true
-    },
-    "source-map": {
-      "version": "0.5.7",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-      "dev": true
-    },
-    "sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
-    },
-    "string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "5.1.2"
-      }
-    },
-    "stylis": {
-      "version": "3.5.4",
-      "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz",
-      "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==",
-      "dev": true
-    },
-    "stylis-rule-sheet": {
-      "version": "0.0.10",
-      "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz",
-      "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==",
-      "dev": true
-    },
-    "supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
-      "requires": {
-        "has-flag": "3.0.0"
-      }
-    },
-    "to-fast-properties": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
-      "dev": true
-    },
-    "touch": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/touch/-/touch-2.0.2.tgz",
-      "integrity": "sha512-qjNtvsFXTRq7IuMLweVgFxmEuQ6gLbRs2jQxL80TtZ31dEKWYIxRXquij6w6VimyDek5hD3PytljHmEtAs2u0A==",
-      "dev": true,
-      "requires": {
-        "nopt": "1.0.10"
-      }
-    },
-    "typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
-      "dev": true
-    },
-    "unstated": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/unstated/-/unstated-2.1.1.tgz",
-      "integrity": "sha512-fORlTWMZxq7NuMJDxyIrrYIZKN7wEWYQ9SiaJfIRcSpsowr6Ph/JIfK2tgtXLW614JfPG/t5q9eEIhXRCf55xg==",
-      "dev": true,
-      "requires": {
-        "create-react-context": "0.1.6"
-      }
-    },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
-      "dev": true
-    }
-  }
-}
diff --git a/wax-prosemirror-core/package.json b/wax-prosemirror-core/package.json
index ceb04f8d09e16a790bceb7ad603191a6e34ccbc6..00f69f138c4842b858b109cd5db2e79a39e9e438 100644
--- a/wax-prosemirror-core/package.json
+++ b/wax-prosemirror-core/package.json
@@ -23,7 +23,12 @@
     "prosemirror-view": "^1.13.4",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
-    "styled-components": "^4.2.0"
+    "styled-components": "^4.2.0",
+    "inversify": "^5.0.1",
+    "inversify-inject-decorators": "^3.1.0",
+    "reflect-metadata": "^0.1.13",
+    "wax-prosemirror-services": "^0.0.3",
+    "deepmerge": "^4.2.2"
   },
   "devDependencies": {
     "mocha": "^3.4.2",
diff --git a/wax-prosemirror-core/src/Application.js b/wax-prosemirror-core/src/Application.js
new file mode 100644
index 0000000000000000000000000000000000000000..6b16d39f4c4c25114aa2cce0aed15fa6d09ae4dc
--- /dev/null
+++ b/wax-prosemirror-core/src/Application.js
@@ -0,0 +1,104 @@
+import { Container } from "inversify";
+import "reflect-metadata";
+import deepmerge from "deepmerge";
+import Config from "./config/Config";
+import defaultConfig from "./config/defaultConfig";
+import PmPlugins from "./PmPlugins";
+
+export default class Application {
+  container = {};
+  config = {};
+  PmPlugins = {};
+  schema = {};
+
+  constructor(container) {
+    this.container = container;
+    this.PmPlugins = container.get("PmPlugins");
+  }
+
+  registerServices() {
+    let count = 0;
+    while (count < this.config.get("services").length) {
+      const service = this.config.get("services")[count];
+      /*
+        set App to every service
+        so services can have access to containers and config
+        */
+      service.setApp(this);
+
+      if (service.dependencies) {
+        this.config.pushToArray("services", service.dependencies);
+      }
+
+      if (service.register) {
+        service.register();
+      }
+
+      count += 1;
+    }
+  }
+
+  setConfig(config) {
+    this.config = this.container.get("Config");
+    Object.keys(config).forEach(conf => {
+      this.config = this.config.pushToArray(conf, config[conf]);
+    });
+  }
+
+  bootServices() {
+    const services = this.config.get("services");
+    services.forEach(plugin => {
+      if (plugin.boot) {
+        plugin.boot();
+      }
+    });
+  }
+
+  getPlugins() {
+    return this.PmPlugins.getAll();
+  }
+
+  getSchema() {
+    this.schema = this.container.get("Schema");
+    return this.schema.getSchema();
+  }
+
+  static create(config) {
+    /*
+    Create Container
+    */
+    const container = new Container();
+    const configPlugins = config.config.PmPlugins;
+    /*
+    Set base bindings for the App to work
+    */
+    container
+      .bind("PmPlugins")
+      .to(PmPlugins)
+      .inSingletonScope();
+
+    container.bind("Wax").toFactory(() => new Application(container));
+
+    defaultConfig.services = defaultConfig.services.concat(
+      config.config.services
+    );
+
+    container.bind("config").toConstantValue(defaultConfig);
+    container
+      .bind("Config")
+      .to(Config)
+      .inSingletonScope();
+
+    /*
+    Start the App
+    */
+    const app = container.get("Wax");
+    app.setConfig(config);
+    configPlugins.forEach(configPlugin => {
+      app.PmPlugins.add(configPlugin.key, configPlugin);
+    });
+    app.registerServices();
+
+    return app;
+  }
+}
diff --git a/wax-prosemirror-core/src/FootnoteView.js b/wax-prosemirror-core/src/FootnoteView.js
new file mode 100644
index 0000000000000000000000000000000000000000..807409849eb3d5d8ac8128577128dc655800b3a8
--- /dev/null
+++ b/wax-prosemirror-core/src/FootnoteView.js
@@ -0,0 +1,119 @@
+import { StepMap } from "prosemirror-transform";
+import { keymap } from "prosemirror-keymap";
+import { undo, redo } from "prosemirror-history";
+import { EditorView } from "prosemirror-view";
+import { EditorState } from "prosemirror-state";
+import { Schema } from "prosemirror-model";
+import { DefaultSchema } from "wax-prosemirror-schema";
+
+class FootnoteView {
+  constructor(node, view, getPos) {
+    console.log(node);
+    // We'll need these later
+    this.node = node;
+
+    this.outerView = view;
+    this.getPos = getPos;
+
+    // The node's representation in the editor (empty, for now)
+    this.dom = document.createElement("footnote");
+    // These are used when the footnote is selected
+    this.innerView = null;
+  }
+  selectNode() {
+    this.dom.classList.add("ProseMirror-selectednode");
+
+    if (!this.innerView) this.open();
+  }
+
+  deselectNode() {
+    this.dom.classList.remove("ProseMirror-selectednode");
+    if (this.innerView) this.close();
+  }
+
+  open() {
+    // Append a tooltip to the outer node
+    let tooltip = this.dom.appendChild(document.createElement("div"));
+    tooltip.className = "footnote-tooltip";
+    // And put a sub-ProseMirror into that
+    this.innerView = new EditorView(tooltip, {
+      // You can use any node as an editor document
+      state: EditorState.create({
+        doc: this.node,
+        plugins: [
+          keymap({
+            "Mod-z": () => undo(this.outerView.state, this.outerView.dispatch),
+            "Mod-y": () => redo(this.outerView.state, this.outerView.dispatch)
+          })
+        ]
+      }),
+      // This is the magic part
+      dispatchTransaction: this.dispatchInner.bind(this),
+      handleDOMEvents: {
+        mousedown: () => {
+          // Kludge to prevent issues due to the fact that the whole
+          // footnote is node-selected (and thus DOM-selected) when
+          // the parent editor is focused.
+          if (this.outerView.hasFocus()) this.innerView.focus();
+        }
+      }
+    });
+  }
+
+  close() {
+    this.innerView.destroy();
+    this.innerView = null;
+    this.dom.textContent = "";
+  }
+  dispatchInner(tr) {
+    let { state, transactions } = this.innerView.state.applyTransaction(tr);
+    this.innerView.updateState(state);
+
+    if (!tr.getMeta("fromOutside")) {
+      let outerTr = this.outerView.state.tr,
+        offsetMap = StepMap.offset(this.getPos() + 1);
+      for (let i = 0; i < transactions.length; i++) {
+        let steps = transactions[i].steps;
+        for (let j = 0; j < steps.length; j++)
+          outerTr.step(steps[j].map(offsetMap));
+      }
+      if (outerTr.docChanged) this.outerView.dispatch(outerTr);
+    }
+  }
+  update(node) {
+    console.log("update");
+    if (!node.sameMarkup(this.node)) return false;
+    this.node = node;
+    if (this.innerView) {
+      let state = this.innerView.state;
+      let start = node.content.findDiffStart(state.doc.content);
+      if (start != null) {
+        let { a: endA, b: endB } = node.content.findDiffEnd(state.doc.content);
+        let overlap = start - Math.min(endA, endB);
+        if (overlap > 0) {
+          endA += overlap;
+          endB += overlap;
+        }
+        this.innerView.dispatch(
+          state.tr
+            .replace(start, endB, node.slice(start, endA))
+            .setMeta("fromOutside", true)
+        );
+      }
+    }
+    return true;
+  }
+  destroy() {
+    if (this.innerView) this.close();
+  }
+
+  stopEvent(event) {
+    return this.innerView && this.innerView.dom.contains(event.target);
+  }
+
+  ignoreMutation() {
+    return true;
+  }
+}
+
+export default FootnoteView;
diff --git a/wax-prosemirror-core/src/PmPlugins.js b/wax-prosemirror-core/src/PmPlugins.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac5b5bf562166fbbaca25ff0f027732a8385761a
--- /dev/null
+++ b/wax-prosemirror-core/src/PmPlugins.js
@@ -0,0 +1,16 @@
+import { injectable } from "inversify";
+@injectable()
+export default class PmPlugins {
+  _plugins = new Map();
+  add(key, plugin) {
+    this._plugins.set(key, plugin);
+  }
+
+  getAll() {
+    return [...this._plugins.values()];
+  }
+
+  get(key) {
+    return this._plugins.get(key);
+  }
+}
diff --git a/wax-prosemirror-core/src/Wax.js b/wax-prosemirror-core/src/Wax.js
index 10306578d5a983a0c9e13abb78704ec15de3d177..5f63e56925d2d33e360786d849f6786ab0352246 100644
--- a/wax-prosemirror-core/src/Wax.js
+++ b/wax-prosemirror-core/src/Wax.js
@@ -1,15 +1,15 @@
-import React, { Fragment, Component } from "react";
+import React, { Component } from "react";
+import WaxProvider from "./ioc-react";
+import Application from "./Application";
+
 import debounce from "lodash/debounce";
 import styled from "styled-components";
 
 import { DOMParser, DOMSerializer } from "prosemirror-model";
 
 import WaxView from "./WaxView";
-import defaultPlugins from "./config/defaultPlugins";
-import placeholder from "./config/plugins/placeholder";
-
-import CreateShortCuts from "./config/classes/CreateShortCuts";
-import CreateRules from "./config/classes/CreateRules";
+import defaultPlugins from "./plugins/defaultPlugins";
+import placeholder from "./plugins/placeholder";
 
 const parser = schema => {
   const parser = DOMParser.fromSchema(schema);
@@ -38,25 +38,21 @@ const LayoutWrapper = styled.div`
 `;
 
 class Wax extends Component {
-  componentWillMount() {
-    const { value, onChange, options } = this.props;
-    const { schema, plugins, keys, rules } = options;
-    const WaxOnchange = onChange ? onChange : value => true;
+  application = {};
+  constructor(props) {
+    super(props);
+    this.application = Application.create(props);
+    const schema = this.application.getSchema();
+    this.application.bootServices();
+    const { value, onChange } = this.props;
 
-    const WaxShortCuts = keys
-      ? keys
-      : new CreateShortCuts({ schema: schema, shortCuts: {} });
-
-    const WaxRules = new CreateRules({ schema: schema, rules: rules });
+    const WaxOnchange = onChange ? onChange : value => true;
 
     const editorContent = value ? value : "";
 
-    if (plugins) defaultPlugins.push(...plugins);
-
     const finalPlugins = defaultPlugins.concat([
       placeholder({ content: this.props.placeholder }),
-      WaxShortCuts,
-      WaxRules
+      ...this.application.getPlugins()
     ]);
 
     this.WaxOptions = {
@@ -80,42 +76,40 @@ class Wax extends Component {
   render() {
     const {
       autoFocus,
-      children,
-      placeholder,
-      renderLayout,
-      fileUpload,
-      readonly,
       className,
-      value,
-      onBlur,
-      layout,
-      theme,
       debug,
+      fileUpload,
+      layout,
+      onBlur,
+      placeholder,
+      readonly,
       TrackChange,
+      value,
       user
     } = this.props;
 
-    const defaultRender = ({ editor, state, dispatch, fileUpload }) => (
-      <Fragment>{editor}</Fragment>
-    );
+    const Layout = this.application.container.get("Layout");
+    if (layout) Layout.setLayout(layout);
+    const WaxRender = Layout.layoutComponent;
 
-    const WaxRender = children ? children : defaultRender;
     return (
       <LayoutWrapper className={`${className}`}>
-        <WaxView
-          autoFocus={autoFocus}
-          readonly={readonly}
-          options={this.WaxOptions}
-          placeholder={placeholder}
-          fileUpload={fileUpload}
-          onBlur={onBlur || (value => true)}
-          onChange={this.onChange || (value => true)}
-          debug={debug}
-          TrackChange={TrackChange}
-          user={user}
-        >
-          {WaxRender}
-        </WaxView>
+        <WaxProvider app={this.application}>
+          <WaxView
+            autoFocus={autoFocus}
+            readonly={readonly}
+            options={this.WaxOptions}
+            placeholder={placeholder}
+            fileUpload={fileUpload}
+            onBlur={onBlur || (value => true)}
+            onChange={this.onChange || (value => true)}
+            debug={debug}
+            TrackChange={TrackChange}
+            user={user}
+          >
+            {({ editor }) => <WaxRender editor={editor} />}
+          </WaxView>
+        </WaxProvider>
       </LayoutWrapper>
     );
   }
diff --git a/wax-prosemirror-core/src/WaxView.js b/wax-prosemirror-core/src/WaxView.js
index afc9eb25d17d0edd5b233eada40c6c2066a136c9..e21b7a5bc229ccaafee8645f63782a7a309dc9da 100644
--- a/wax-prosemirror-core/src/WaxView.js
+++ b/wax-prosemirror-core/src/WaxView.js
@@ -1,116 +1,66 @@
-import React, { Component } from "react";
-import applyDevTools from "prosemirror-dev-tools";
+import React, {
+  useEffect,
+  useState,
+  useRef,
+  useContext,
+  Component
+} from "react";
 
+import applyDevTools from "prosemirror-dev-tools";
 import { EditorState } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
-
-import placeholderPlugin from "./config/plugins/placeholderPlugin";
 import "prosemirror-view/style/prosemirror.css";
-import trackedTransaction from "./config/track-changes/trackedTransaction";
-
-class WaxView extends Component {
-  constructor(props) {
-    super(props);
-    const { readonly, onBlur } = this.props;
-
-    this.editorRef = React.createRef();
-
-    // Create view of Editor
-    this.view = new EditorView(null, {
-      editable: () => !readonly,
-      state: EditorState.create(props.options),
-      dispatchTransaction: this.dispatchTransaction,
-      fileUpload: this.uploadImage,
-      handleDOMEvents: {
-        blur: onBlur
-          ? view => {
-              onBlur(view.state.doc.content);
-            }
-          : null
-      }
-    });
-  }
-
-  componentDidMount() {
-    const { autoFocus, debug } = this.props;
-    this.editorRef.current.appendChild(this.view.dom);
 
-    if (debug) applyDevTools(this.view);
-    if (autoFocus) this.view.focus();
-  }
-
-  uploadImage = file => {
-    const { state } = this.view;
-    const { findPlaceholder } = this;
-    const { fileUpload } = this.props;
-
-    // A fresh object to act as the ID for this upload
-    const id = {};
-
-    // Replace the selection with a placeholder
-    const { tr } = state;
-    if (!tr.selection.empty) tr.deleteSelection();
-
-    tr.setMeta(placeholderPlugin, {
-      add: { id, pos: tr.selection.from }
-    });
-
-    this.view.dispatch(tr);
-
-    fileUpload(file).then(
-      url => {
-        const pos = findPlaceholder(this.view.state, id);
-        // If the content around the placeholder has been deleted, drop
-        // the image
-        if (pos == null) {
-          return;
+import trackedTransaction from "./track-changes/trackedTransaction";
+import { WaxContext } from "./ioc-react";
+import FootnoteView from "./FootnoteView";
+
+export default props => {
+  const { readonly, onBlur, options, debug, autoFocus } = props;
+  const editorRef = useRef();
+
+  const context = useContext(WaxContext);
+
+  useEffect(() => {
+    const view = new EditorView(
+      { mount: editorRef.current },
+      {
+        editable: () => !readonly,
+        state: EditorState.create(options),
+        dispatchTransaction: transaction => {
+          const { TrackChange } = props;
+          const tr = TrackChange
+            ? trackedTransaction(transaction, view.state, this)
+            : transaction;
+
+          const state = view.state.apply(tr);
+          view.updateState(state);
+          context.updateView({ main: view });
+
+          props.onChange(state.doc.content);
+        },
+        handleDOMEvents: {
+          blur: onBlur
+            ? view => {
+                onBlur(view.state.doc.content);
+              }
+            : null
         }
-        // Otherwise, insert it at the placeholder's position, and remove
-        // the placeholder
-        this.view.dispatch(
-          state.tr
-            .replaceWith(
-              pos,
-              pos,
-              this.view.state.schema.nodes.image.create({
-                src: url
-              })
-            )
-            .setMeta(placeholderPlugin, { remove: { id } })
-        );
-      },
-      () => {
-        // On failure, just clean up the placeholder
-        this.view.dispatch(tr.setMeta(placeholderPlugin, { remove: { id } }));
+        // nodeViews: {
+        //   footnote(node, view, getPos) {
+        //     return new FootnoteView(node, view, getPos);
+        //   }
+        // }
       }
     );
-  };
-
-  findPlaceholder = (state, id) => {
-    const decos = placeholderPlugin.getState(state);
-    const found = decos.find(null, null, spec => spec.id === id);
-    return found.length ? found[0].from : null;
-  };
-
-  dispatchTransaction = transaction => {
-    const { TrackChange } = this.props;
-    const tr = TrackChange
-      ? trackedTransaction(transaction, this.view.state, this)
-      : transaction;
-    const state = this.view.state.apply(tr);
-    this.view.updateState(state);
-    this.props.onChange(state.doc.content);
-    this.forceUpdate();
-  };
+    context.updateView({ main: view });
 
-  render() {
-    const editor = <span ref={this.editorRef} />;
-    return this.props.children({
-      view: this.view,
-      fileUpload: this.uploadImage,
-      editor
-    });
-  }
-}
+    if (debug) applyDevTools(view);
+    if (autoFocus) view.focus();
+  }, []);
 
-export default WaxView;
+  const editor = <div ref={editorRef} />;
+  return props.children({
+    editor
+  });
+};
diff --git a/wax-prosemirror-core/src/config/Config.js b/wax-prosemirror-core/src/config/Config.js
new file mode 100644
index 0000000000000000000000000000000000000000..d55a3be453aabd745a7450aed56e1ef85c7d8fbe
--- /dev/null
+++ b/wax-prosemirror-core/src/config/Config.js
@@ -0,0 +1,36 @@
+import { set, get, isArrayLikeObject } from "lodash";
+import { injectable, inject } from "inversify";
+
+@injectable()
+export default class Config {
+  _config = {};
+  constructor(@inject("config") config) {
+    this._config = config;
+  }
+
+  set(key, value) {
+    set(this._config, key, value);
+    return this._config;
+  }
+
+  get(key) {
+    return get(this._config, key);
+  }
+
+  pushToArray(key, value) {
+    let oldValue = this.get(key);
+    if (oldValue) {
+      if (isArrayLikeObject(value)) {
+        value.forEach(v => {
+          oldValue.push(v);
+        });
+      } else {
+        oldValue.push(value);
+      }
+    } else {
+      oldValue = value;
+    }
+    this.set(key, oldValue);
+    return this;
+  }
+}
diff --git a/wax-prosemirror-core/src/config/classes/CreateRules.js b/wax-prosemirror-core/src/config/classes/CreateRules.js
deleted file mode 100644
index 4475237b20fb6991ec21ba7992961db1a969eeb3..0000000000000000000000000000000000000000
--- a/wax-prosemirror-core/src/config/classes/CreateRules.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import {
-  inputRules,
-  wrappingInputRule,
-  textblockTypeInputRule,
-  smartQuotes
-} from "prosemirror-inputrules";
-
-class CreateRules {
-  constructor(config) {
-    this.rules = config.rules;
-    this.schema = config.schema;
-    return inputRules(this.allRules(this.rules));
-  }
-
-  allRules(rules = []) {
-    return {
-      rules: [
-        ...smartQuotes,
-        ...rules,
-        // > blockquote
-        wrappingInputRule(/^\s*>\s$/, this.schema.nodes.blockquote),
-
-        // 1. ordered list
-        wrappingInputRule(
-          /^(\d+)\.\s$/,
-          this.schema.nodes.ordered_list,
-          match => ({ order: +match[1] }),
-          (match, node) => node.childCount + node.attrs.order === +match[1]
-        ),
-
-        // * bullet list
-        wrappingInputRule(/^\s*([-+*])\s$/, this.schema.nodes.bullet_list),
-
-        // ``` code block
-        textblockTypeInputRule(/^```$/, this.schema.nodes.code_block),
-
-        // # heading
-        textblockTypeInputRule(
-          new RegExp("^(#{1,6})\\s$"),
-          this.schema.nodes.heading,
-          match => ({ level: match[1].length })
-        )
-      ]
-    };
-  }
-}
-
-export default CreateRules;
diff --git a/wax-prosemirror-core/src/config/classes/CreateSchema.js b/wax-prosemirror-core/src/config/classes/CreateSchema.js
deleted file mode 100644
index b192c4f80ed96a11eb0e87991f84c5bc1d4038e7..0000000000000000000000000000000000000000
--- a/wax-prosemirror-core/src/config/classes/CreateSchema.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Schema } from "prosemirror-model";
-
-class CreateSchema {
-  constructor(schema) {
-    if (!schema) {
-      throw new Error("schema is mandatory");
-    }
-    const { nodes, marks } = schema;
-
-    if (!nodes || !marks) {
-      throw new Error("no nodes or marks found");
-    }
-
-    this.nodes = nodes;
-    this.marks = marks;
-    return this.initSchema();
-  }
-
-  initSchema() {
-    return new Schema(this.toJSON());
-  }
-
-  toJSON() {
-    return {
-      nodes: this.nodes,
-      marks: this.marks
-    };
-  }
-
-  setDefaultSchema() {}
-}
-
-export default CreateSchema;
diff --git a/wax-prosemirror-core/src/config/defaultConfig.js b/wax-prosemirror-core/src/config/defaultConfig.js
new file mode 100644
index 0000000000000000000000000000000000000000..d006ad5ed7ffafa2df0192e7d1b1fe9e82042847
--- /dev/null
+++ b/wax-prosemirror-core/src/config/defaultConfig.js
@@ -0,0 +1,17 @@
+import LayoutService from "../services/LayoutService/LayoutService";
+import {
+  SchemaService,
+  MenuService,
+  RulesService,
+  ShortCutsService
+} from "wax-prosemirror-services";
+
+export default {
+  services: [
+    new SchemaService(),
+    new RulesService(),
+    new ShortCutsService(),
+    new LayoutService(),
+    new MenuService()
+  ]
+};
diff --git a/wax-prosemirror-core/src/config/plugins/placeholderPlugin.js b/wax-prosemirror-core/src/config/plugins/placeholderPlugin.js
deleted file mode 100644
index b7c11f625a375e3f94fdea17398e89ea74730fe8..0000000000000000000000000000000000000000
--- a/wax-prosemirror-core/src/config/plugins/placeholderPlugin.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { Plugin, PluginKey } from "prosemirror-state";
-import { Decoration, DecorationSet } from "prosemirror-view";
-
-const placeHolder = new PluginKey("placeHolder");
-
-const placeholderPlugin = new Plugin({
-  key: placeHolder,
-  state: {
-    init: function init() {
-      return DecorationSet.empty;
-    },
-    apply: function apply(tr, set) {
-      // Adjust decoration positions to changes made by the transaction
-      set = set.map(tr.mapping, tr.doc);
-      // See if the transaction adds or removes any placeholders
-      const action = tr.getMeta(this);
-      if (action && action.add) {
-        const widget = document.createElement("placeholder");
-        const deco = Decoration.widget(action.add.pos, widget, {
-          id: action.add.id
-        });
-        set = set.add(tr.doc, [deco]);
-      } else if (action && action.remove) {
-        set = set.remove(
-          set.find(null, null, spec => spec.id === action.remove.id)
-        );
-      }
-      return set;
-    }
-  },
-  props: {
-    decorations: function decorations(state) {
-      return this.getState(state);
-    }
-  }
-});
-
-export default placeholderPlugin;
diff --git a/wax-prosemirror-core/src/ioc-react.js b/wax-prosemirror-core/src/ioc-react.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c8acff8fff9f82323a4f8274346060862d2bd4b
--- /dev/null
+++ b/wax-prosemirror-core/src/ioc-react.js
@@ -0,0 +1,41 @@
+import React, { useContext, useState } from "react";
+
+export const WaxContext = React.createContext({
+  view: {},
+  app: null,
+  updateView: null
+});
+
+export default props => {
+  const [context, setContext] = useState({
+    app: props.app,
+    view: props.view || {},
+    updateView: view => {
+      setContext({ ...context, view: Object.assign(context.view, view) });
+    }
+  });
+
+  return (
+    <WaxContext.Provider
+      value={{
+        ...context
+      }}
+    >
+      {props.children}
+    </WaxContext.Provider>
+  );
+};
+
+export const useInjection = identifier => {
+  const {
+    app: { container }
+  } = useContext(WaxContext);
+
+  if (!container) {
+    throw new Error();
+  }
+
+  return container.isBound(identifier)
+    ? { instance: container.get(identifier) }
+    : null;
+};
diff --git a/wax-prosemirror-core/src/config/defaultPlugins.js b/wax-prosemirror-core/src/plugins/defaultPlugins.js
similarity index 60%
rename from wax-prosemirror-core/src/config/defaultPlugins.js
rename to wax-prosemirror-core/src/plugins/defaultPlugins.js
index 0925929427a4034bd7f961d97af61f057c92ef49..7ec2465b647eeac3a32b8e181381b9b3d4c1b963 100644
--- a/wax-prosemirror-core/src/config/defaultPlugins.js
+++ b/wax-prosemirror-core/src/plugins/defaultPlugins.js
@@ -2,6 +2,5 @@ import { history } from "prosemirror-history";
 import { dropCursor } from "prosemirror-dropcursor";
 import { gapCursor } from "prosemirror-gapcursor";
 import "prosemirror-gapcursor/style/gapcursor.css";
-import placeholderPlugin from "./plugins/placeholderPlugin";
 
-export default [dropCursor(), gapCursor(), history(), placeholderPlugin];
+export default [dropCursor(), gapCursor(), history()];
diff --git a/wax-prosemirror-core/src/config/plugins/placeholder.js b/wax-prosemirror-core/src/plugins/placeholder.js
similarity index 100%
rename from wax-prosemirror-core/src/config/plugins/placeholder.js
rename to wax-prosemirror-core/src/plugins/placeholder.js
diff --git a/wax-prosemirror-core/src/services/LayoutService/Layout.js b/wax-prosemirror-core/src/services/LayoutService/Layout.js
new file mode 100644
index 0000000000000000000000000000000000000000..734a53f7b712535e99e0b8c85007ce2497e766df
--- /dev/null
+++ b/wax-prosemirror-core/src/services/LayoutService/Layout.js
@@ -0,0 +1,36 @@
+import { injectable } from "inversify";
+import { DefaultLayout } from "wax-prosemirror-layouts";
+import LayoutFactory from "./components/LayoutFactory";
+
+@injectable()
+export default class Layout {
+  components = [];
+  layoutComponent = LayoutFactory(DefaultLayout);
+  addComponent(renderArea, component) {
+    if (!this.components[renderArea]) {
+      this.createArea(renderArea);
+    }
+    const size = this.components[renderArea].size;
+    this.components[renderArea].set(size + 1, component);
+    return this;
+  }
+
+  render(renderArea) {
+    if (!this.components[renderArea]) return null;
+    return this.getArray(this.components[renderArea]);
+  }
+
+  createArea(area) {
+    this.components[area] = new Map();
+  }
+
+  getArray(iterator) {
+    const components = [];
+    iterator.forEach(component => components.push(component));
+    return components;
+  }
+
+  setLayout(component) {
+    this.layoutComponent = LayoutFactory(component);
+  }
+}
diff --git a/wax-prosemirror-core/src/services/LayoutService/LayoutService.js b/wax-prosemirror-core/src/services/LayoutService/LayoutService.js
new file mode 100644
index 0000000000000000000000000000000000000000..38183390157414490b8c1d55831050cb81c56625
--- /dev/null
+++ b/wax-prosemirror-core/src/services/LayoutService/LayoutService.js
@@ -0,0 +1,12 @@
+import Service from "../Service";
+import Layout from "./Layout";
+export default class LayoutService extends Service {
+  name = "LayoutService";
+
+  register() {
+    this.container
+      .bind("Layout")
+      .to(Layout)
+      .inSingletonScope();
+  }
+}
diff --git a/wax-prosemirror-core/src/services/LayoutService/components/LayoutFactory.js b/wax-prosemirror-core/src/services/LayoutService/components/LayoutFactory.js
new file mode 100644
index 0000000000000000000000000000000000000000..776982f7b6ae1a8245011e603c0d1471d676b222
--- /dev/null
+++ b/wax-prosemirror-core/src/services/LayoutService/components/LayoutFactory.js
@@ -0,0 +1,3 @@
+import React from "react";
+
+export default Component => props => <Component {...props} />;
diff --git a/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js b/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..f242dab50c25b4cdc0d11c8429e23f7c9919bd34
--- /dev/null
+++ b/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js
@@ -0,0 +1,32 @@
+import React, { Component } from "react";
+import { useInjection } from "../../../ioc-react";
+class UpdateView extends Component {
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      view: this.props.view
+    };
+  }
+
+  updateView(view) {
+    this.setState(view);
+  }
+
+  render() {
+    return this.props.children({ view: this.state.view });
+  }
+}
+
+const ComponentPlugin = renderArea => props => {
+  const { instance } = useInjection("Layout");
+
+  const components = instance.render(renderArea);
+
+  return components
+    ? components.map((Component, key) => {
+        return <Component key={`${renderArea}-${key}`} />;
+      })
+    : null;
+};
+export default ComponentPlugin;
diff --git a/wax-prosemirror-core/src/services/Service.js b/wax-prosemirror-core/src/services/Service.js
new file mode 100644
index 0000000000000000000000000000000000000000..29454ebc80e71028beee7c2ba57548740b5939ec
--- /dev/null
+++ b/wax-prosemirror-core/src/services/Service.js
@@ -0,0 +1,18 @@
+export default class Service {
+  app = {};
+  setApp(app) {
+    this.app = app;
+  }
+
+  get container() {
+    return this.app.container;
+  }
+
+  get config() {
+    return this.app.config.get(`config.${this.name}`) || this.app.config;
+  }
+
+  get schema() {
+    return this.app.getSchema();
+  }
+}
diff --git a/wax-prosemirror-core/src/config/track-changes/markDeletion.js b/wax-prosemirror-core/src/track-changes/markDeletion.js
similarity index 100%
rename from wax-prosemirror-core/src/config/track-changes/markDeletion.js
rename to wax-prosemirror-core/src/track-changes/markDeletion.js
diff --git a/wax-prosemirror-core/src/config/track-changes/markInsertion.js b/wax-prosemirror-core/src/track-changes/markInsertion.js
similarity index 100%
rename from wax-prosemirror-core/src/config/track-changes/markInsertion.js
rename to wax-prosemirror-core/src/track-changes/markInsertion.js
diff --git a/wax-prosemirror-core/src/config/track-changes/markWrapping.js b/wax-prosemirror-core/src/track-changes/markWrapping.js
similarity index 100%
rename from wax-prosemirror-core/src/config/track-changes/markWrapping.js
rename to wax-prosemirror-core/src/track-changes/markWrapping.js
diff --git a/wax-prosemirror-core/src/config/track-changes/trackedTransaction.js b/wax-prosemirror-core/src/track-changes/trackedTransaction.js
similarity index 100%
rename from wax-prosemirror-core/src/config/track-changes/trackedTransaction.js
rename to wax-prosemirror-core/src/track-changes/trackedTransaction.js
diff --git a/wax-prosemirror-layouts/index.js b/wax-prosemirror-layouts/index.js
index c48bf92d52569f9696a1c5f88dbf4805f7469279..6ea69e16ea2c99700e74539eb2310489deb0ecbf 100644
--- a/wax-prosemirror-layouts/index.js
+++ b/wax-prosemirror-layouts/index.js
@@ -1 +1,2 @@
 export { default as EditoriaLayout } from "./src/layouts/EditoriaLayout";
+export { default as DefaultLayout } from "./src/layouts/DefaultLayout";
diff --git a/wax-prosemirror-layouts/src/layouts/DefaultLayout.js b/wax-prosemirror-layouts/src/layouts/DefaultLayout.js
new file mode 100644
index 0000000000000000000000000000000000000000..7eb3ae47691c990f78bd140ba0610dd216d6bcfd
--- /dev/null
+++ b/wax-prosemirror-layouts/src/layouts/DefaultLayout.js
@@ -0,0 +1,5 @@
+import React, { Fragment } from "react";
+
+const DefaultLayout = ({ editor }) => <Fragment>{editor}</Fragment>;
+
+export default DefaultLayout;
diff --git a/wax-prosemirror-layouts/src/layouts/EditorElements.js b/wax-prosemirror-layouts/src/layouts/EditorElements.js
index 0e771f795ab3ad4cfd99e82b2d46b83fc579db99..2955279069485125598e6bbccc98758b450f0f8e 100644
--- a/wax-prosemirror-layouts/src/layouts/EditorElements.js
+++ b/wax-prosemirror-layouts/src/layouts/EditorElements.js
@@ -2,7 +2,52 @@ import styled, { css } from "styled-components";
 
 /* All styles regarding ProseMirror surface and elements */
 
-export default css`{
+export default css`
+  .ProseMirror footnote {
+    display: inline-block;
+    position: relative;
+    cursor: pointer;
+  }
+
+  .ProseMirror footnote::after {
+    content: counter(footnote);
+    vertical-align: super;
+    font-size: 75%;
+    counter-increment: footnote;
+  }
+
+  .ProseMirror-hideselection .footnote-tooltip *::selection {
+    background-color: transparent;
+  }
+
+  .ProseMirror-hideselection .footnote-tooltip *::-moz-selection {
+    background-color: transparent;
+  }
+
+  .ProseMirror .footnote-tooltip {
+    cursor: auto;
+    position: absolute;
+    left: -30px;
+    top: calc(100% + 10px);
+    background: silver;
+    padding: 3px;
+    border-radius: 2px;
+    width: 500px;
+  }
+
+  .ProseMirror .footnote-tooltip::before {
+    border: 5px solid silver;
+    border-top-width: 0;
+    border-left-color: transparent;
+    border-right-color: transparent;
+    position: absolute;
+    top: -5px;
+    left: 27px;
+    content: " ";
+    height: 0;
+    width: 0;
+  }
+
   .ProseMirror {
     -moz-box-shadow: 0 0 3px #ccc;
     -webkit-box-shadow: 0 0 3px #ccc;
diff --git a/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js b/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js
index 5f4c4dd0b2a36558bf455bba44e8d0b632ed3a47..771dcf12d110aebf079ed7e4e5956706427a2d14 100644
--- a/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js
+++ b/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js
@@ -1,6 +1,7 @@
+import React, { useMemo, Component } from "react";
 import styled, { ThemeProvider } from "styled-components";
-import React, { Fragment } from "react";
-import { MainMenuBar, SideMenuBar, InfoArea } from "wax-prosemirror-components";
+import { InfoArea } from "wax-prosemirror-components";
+import { componentPlugin, Service } from "wax-prosemirror-core";
 import EditorElements from "./EditorElements";
 import { cokoTheme } from "wax-prosemirror-themes";
 
@@ -33,22 +34,88 @@ const WaxSurfaceScroll = styled.div`
   ${EditorElements};
 `;
 
-const CommentsContainer = styled.div``;
-const NotesContainer = styled.div``;
-
-const EditoriaLayout = ({ editor, view, ...props }) => (
-  <ThemeProvider theme={cokoTheme}>
-    <LayoutWrapper>
-      <MainMenuBar view={view} {...props} />
-      <WaxSurfaceContainer>
-        <SideMenuBar view={view} {...props} />
-        <WaxSurfaceScroll className="wax-surface-scroll">
-          {editor}
-        </WaxSurfaceScroll>
-      </WaxSurfaceContainer>
-      <InfoArea />
-    </LayoutWrapper>
-  </ThemeProvider>
-);
+const MainMenuContainer = styled.div`
+  background: #fff;
+  height: 52px;
+  line-height: 32px;
+  position: relative;
+  user-select: none;
+`;
+const MainMenuInner = styled.div`
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  background: transparent;
+  z-index: 9999;
+  div {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+`;
+
+const SideMenuContainer = styled.div`
+  display: flex;
+  width: 14%;
+  height: 98%;
+`;
+
+const SideMenuInner = styled.div`
+  display: flex;
+  width: 100%;
+  > div {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    margin-top: 15px;
+    button {
+      display: flex;
+      flex-direction: column;
+      font-family: ${props => props.theme.fontInterface};
+      margin-left: 5%;
+      width: 90%;
+    }
+  }
+`;
+
+const LeftSideBar = componentPlugin("leftSideBar");
+const RightSideBar = componentPlugin("rightSideBar");
+const TopBar = componentPlugin("topBar");
+const BottomBar = componentPlugin("bottomBar");
+const WaxOverlays = componentPlugin("waxOverlays");
+
+const EditoriaLayout = ({ editor }) => {
+  return (
+    <ThemeProvider theme={cokoTheme}>
+      <LayoutWrapper>
+        <MainMenuContainer>
+          <MainMenuInner>
+            <TopBar />
+          </MainMenuInner>
+        </MainMenuContainer>
+        <WaxSurfaceContainer>
+          <SideMenuContainer>
+            <SideMenuInner>
+              <LeftSideBar />
+            </SideMenuInner>
+          </SideMenuContainer>
+          <WaxSurfaceScroll className="wax-surface-scroll">
+            {editor}
+            <WaxOverlays />
+          </WaxSurfaceScroll>
+          <RightSideBar />
+        </WaxSurfaceContainer>
+        <BottomBar />
+        <InfoArea />
+      </LayoutWrapper>
+    </ThemeProvider>
+  );
+};
 
 export default EditoriaLayout;
diff --git a/wax-prosemirror-plugins/jsconfig.json b/wax-prosemirror-plugins/jsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..504cd646e14906b4db8e943f9bfb10ab80162cee
--- /dev/null
+++ b/wax-prosemirror-plugins/jsconfig.json
@@ -0,0 +1,5 @@
+{
+  "compilerOptions": {
+    "experimentalDecorators": true
+  }
+}
diff --git a/wax-prosemirror-plugins/package.json b/wax-prosemirror-plugins/package.json
index eedc5ee50e80506389d1cfa7d5c9c4616c5080dd..f4b4f0164fca2b37c041e1425cd94057e4414ef7 100644
--- a/wax-prosemirror-plugins/package.json
+++ b/wax-prosemirror-plugins/package.json
@@ -10,6 +10,9 @@
   },
   "dependencies": {
     "prosemirror-state": "^1.2.2",
-    "prosemirror-view": "^1.13.1"
+    "prosemirror-view": "^1.13.1",
+    "wax-prosemirror-layouts": "^0.0.3",
+    "wax-prosemirror-core": "^0.0.3",
+    "wax-prosemirror-components": "^0.0.3"
   }
 }
diff --git a/wax-prosemirror-plugins/src/FindAndReplacePlugin.js b/wax-prosemirror-plugins/src/FindAndReplacePlugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..96b65597222bb19213a5633fb5f8a1b061713bf2
--- /dev/null
+++ b/wax-prosemirror-plugins/src/FindAndReplacePlugin.js
@@ -0,0 +1,107 @@
+import ReactDOM from "react-dom";
+import React from "react";
+import { EditorState, Plugin, PluginKey } from "prosemirror-state";
+import { TextSelection } from "prosemirror-state";
+import { EditorView } from "prosemirror-view";
+
+const Component = ({ state }) => {
+  return <div>11111{state.selection.from}</div>;
+};
+
+const findNodesWithSameMark = (doc, from, to, markType) => {
+  let ii = from;
+  const finder = mark => mark.type === markType;
+  let firstMark = null;
+  let fromNode = null;
+  let toNode = null;
+
+  while (ii <= to) {
+    const node = doc.nodeAt(ii);
+    if (!node || !node.marks) {
+      return null;
+    }
+    const mark = node.marks.find(finder);
+    if (!mark) {
+      return null;
+    }
+    if (firstMark && mark !== firstMark) {
+      return null;
+    }
+    fromNode = fromNode || node;
+    firstMark = firstMark || mark;
+    toNode = node;
+    ii++;
+  }
+
+  let fromPos = from;
+  let toPos = to;
+
+  let jj = 0;
+  ii = from - 1;
+  while (ii > jj) {
+    const node = doc.nodeAt(ii);
+    const mark = node && node.marks.find(finder);
+    if (!mark || mark !== firstMark) {
+      break;
+    }
+    fromPos = ii;
+    fromNode = node;
+    ii--;
+  }
+
+  ii = to + 1;
+  jj = doc.nodeSize - 2;
+  while (ii < jj) {
+    const node = doc.nodeAt(ii);
+    const mark = node && node.marks.find(finder);
+    if (!mark || mark !== firstMark) {
+      break;
+    }
+    toPos = ii;
+    toNode = node;
+    ii++;
+  }
+
+  return {
+    mark: firstMark,
+    from: {
+      node: fromNode,
+      pos: fromPos
+    },
+    to: {
+      node: toNode,
+      pos: toPos
+    }
+  };
+};
+
+const WithStatePlugin = Component => ({ state }) => {
+  // const { doc, selection, schema } = state;
+  // const markType = schema.marks.strong;
+  // if (!markType) {
+  //   return null;
+  // }
+  // const { from, to } = selection;
+  // const result = findNodesWithSameMark(doc, from, to, markType);
+  //return result ? <Component state={state} /> : null;
+  return <Component state={state} />;
+};
+
+export const FindAndReplaceKey = new PluginKey("findandreplace");
+
+const FindAndReplacePlugin = new Plugin({
+  key: FindAndReplaceKey,
+  state: {
+    init() {
+      return {
+        renderArea: "rightSideBar",
+        component: WithStatePlugin(Component)
+      };
+    },
+    apply(tr, oldState, newState) {
+      return this.getState(newState);
+    }
+  }
+});
+
+export default FindAndReplacePlugin;
diff --git a/wax-prosemirror-schema/index.js b/wax-prosemirror-schema/index.js
index b89875b9b3e96355f328988e7ece02c06e3929de..2b4ef9712d75cadbf5da2b70ede53895b678bd56 100644
--- a/wax-prosemirror-schema/index.js
+++ b/wax-prosemirror-schema/index.js
@@ -1,3 +1,42 @@
-export { default as DefaultSchema } from "./src/DefaultSchema";
-export { default as EditoriaSchema } from "./src/editoria/EditoriaSchema";
-export { default as XpubSchema } from "./src/XpubSchema";
+/*
+LIST OF SUPPORTED MARKS
+*/
+export { default as codeMark } from "./src/marks/codeMark";
+export { default as strongMark } from "./src/marks/strongMark";
+export { default as linkMark } from "./src/marks/linkMark";
+export { default as emphasisMark } from "./src/marks/emphasisMark";
+export { default as subscriptMark } from "./src/marks/subscriptMark";
+export { default as superscriptMark } from "./src/marks/superscriptMark";
+export { default as strikethroughMark } from "./src/marks/strikethroughMark";
+export { default as underlineMark } from "./src/marks/underlineMark";
+export { default as smallcapsMark } from "./src/marks/smallcapsMark";
+export { default as sourceMark } from "./src/marks/sourceMark";
+
+/*
+LIST OF TRACK CHANGES MARKS
+*/
+export { default as trackChangesMarks } from "./src/marks/trackChangesMarks";
+
+/*
+LIST OF SUPPORTED NODES
+*/
+export { default as authorNode } from "./src/nodes/authorNode";
+export { default as epigraphPoetryNode } from "./src/nodes/epigraphPoetryNode";
+export { default as epigraphProseNode } from "./src/nodes/epigraphProseNode";
+export { default as sourceNoteNode } from "./src/nodes/sourceNoteNode";
+export { default as paragraphContNode } from "./src/nodes/paragraphContNode";
+export { default as extractProseNode } from "./src/nodes/extractProseNode";
+export { default as extractPoetryNode } from "./src/nodes/extractPoetryNode";
+export { default as titleNode } from "./src/nodes/titleNode";
+export { default as orderedListNode } from "./src/nodes/orderedListNode";
+export { default as bulletListNode } from "./src/nodes/bulletListNode";
+export { default as listItemNode } from "./src/nodes/listItemNode";
+export { default as subTitleNode } from "./src/nodes/subTitleNode";
+export { default as imageNode } from "./src/nodes/imageNode";
+export { default as headingNode } from "./src/nodes/headingNode";
+export { default as blockQuoteNode } from "./src/nodes/blockQuoteNode";
+
+/*
+LIST OF TRACK CHANGES NODES
+*/
+export { default as trackChangesNodes } from "./src/nodes/trackChangesNodes";
diff --git a/wax-prosemirror-schema/src/DefaultSchema.js b/wax-prosemirror-schema/src/DefaultSchema.js
deleted file mode 100644
index 2efc2af2d79507d627ecf4f379196ff316deb040..0000000000000000000000000000000000000000
--- a/wax-prosemirror-schema/src/DefaultSchema.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const pDOM = ["p", 0],
-  brDOM = ["br"];
-const DefaultSchema = {
-  nodes: {
-    doc: {
-      content: "block+"
-    },
-
-    text: {
-      group: "inline"
-    },
-
-    hard_break: {
-      inline: true,
-      group: "inline",
-      selectable: false,
-      parseDOM: [{ tag: "br" }],
-      toDOM() {
-        return brDOM;
-      }
-    },
-
-    paragraph: {
-      content: "inline*",
-      group: "block",
-      parseDOM: [{ tag: "p" }],
-      toDOM() {
-        return pDOM;
-      }
-    }
-  },
-  marks: {}
-};
-
-export default DefaultSchema;
diff --git a/wax-prosemirror-schema/src/XpubSchema.js b/wax-prosemirror-schema/src/XpubSchema.js
deleted file mode 100644
index 77fcb1f699b90ca7e1f28ed729fa9f4f94cd7bba..0000000000000000000000000000000000000000
--- a/wax-prosemirror-schema/src/XpubSchema.js
+++ /dev/null
@@ -1,205 +0,0 @@
-import { orderedList, bulletList, listItem } from "prosemirror-schema-list";
-import { tableNodes } from "prosemirror-tables";
-
-const pDOM = ["p", 0],
-  brDOM = ["br"];
-
-const emDOM = ["em", 0],
-  strongDOM = ["strong", 0],
-  codeDOM = ["code", 0];
-
-const XpubSchema = {
-  nodes: {
-    doc: {
-      content: "block+"
-    },
-
-    text: {
-      group: "inline"
-    },
-
-    hard_break: {
-      inline: true,
-      group: "inline",
-      selectable: false,
-      parseDOM: [{ tag: "br" }],
-      toDOM() {
-        return brDOM;
-      }
-    },
-
-    paragraph: {
-      content: "inline*",
-      group: "block",
-      parseDOM: [{ tag: "p" }],
-      toDOM() {
-        return pDOM;
-      }
-    },
-    heading: {
-      attrs: { class: { default: "ct" }, level: { default: 1 } },
-      content: "inline*",
-      group: "block",
-      defining: true,
-      parseDOM: [
-        { tag: "h1", attrs: { level: 1 } },
-        { tag: "h2", attrs: { level: 2 } },
-        { tag: "h3", attrs: { level: 3 } },
-        { tag: "h4", attrs: { level: 4 } },
-        { tag: "h5", attrs: { level: 5 } },
-        { tag: "h6", attrs: { level: 6 } }
-      ],
-      toDOM(node) {
-        if (node.attrs.level === 1) {
-          return ["h" + node.attrs.level, node.attrs, 0];
-        } else {
-          return ["h" + node.attrs.level, 0];
-        }
-      }
-    },
-    image: {
-      inline: true,
-      attrs: {
-        src: {},
-        alt: { default: null },
-        title: { default: null }
-      },
-      group: "inline",
-      draggable: true,
-      parseDOM: [
-        {
-          tag: "img[src]",
-          getAttrs(dom) {
-            return {
-              src: dom.getAttribute("src"),
-              title: dom.getAttribute("title"),
-              alt: dom.getAttribute("alt")
-            };
-          }
-        }
-      ],
-      toDOM(node) {
-        return ["img", node.attrs];
-      }
-    },
-    ordered_list: {
-      ...orderedList,
-      content: "list_item+",
-      group: "block"
-    },
-    bullet_list: {
-      ...bulletList,
-      content: "list_item+",
-      group: "block"
-    },
-    list_item: {
-      ...listItem,
-      content: "paragraph block*",
-      group: "block"
-    }
-  },
-  marks: {
-    link: {
-      attrs: {
-        href: { default: null },
-        rel: { default: "" },
-        target: { default: "blank" },
-        title: { default: null }
-      },
-      inclusive: false,
-      parseDOM: [
-        {
-          tag: "a[href]",
-          getAttrs: dom => {
-            const href = dom.getAttribute("href");
-            const target = href && href.indexOf("#") === 0 ? "" : "blank";
-            return {
-              href: dom.getAttribute("href"),
-              title: dom.getAttribute("title"),
-              target
-            };
-          }
-        }
-      ],
-      toDOM(node) {
-        return ["a", node.attrs, 0];
-      }
-    },
-    em: {
-      parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
-      toDOM() {
-        return emDOM;
-      }
-    },
-    strong: {
-      parseDOM: [
-        { tag: "strong" },
-        {
-          tag: "b",
-          getAttrs: node => node.style.fontWeight != "normal" && null
-        },
-        {
-          style: "font-weight",
-          getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
-        }
-      ],
-      toDOM() {
-        return strongDOM;
-      }
-    },
-    code: {
-      parseDOM: [{ tag: "code" }],
-      toDOM() {
-        return codeDOM;
-      }
-    },
-    subscript: {
-      excludes: "superscript",
-      parseDOM: [{ tag: "sub" }, { style: "vertical-align=sub" }],
-      toDOM: () => ["sub"]
-    },
-    superscript: {
-      excludes: "subscript",
-      parseDOM: [{ tag: "sup" }, { style: "vertical-align=super" }],
-      toDOM: () => ["sup"]
-    },
-    strikethrough: {
-      parseDOM: [
-        { tag: "strike" },
-        { style: "text-decoration:line-through" },
-        { style: "text-decoration-line:line-through" }
-      ],
-      toDOM: () => [
-        "span",
-        {
-          style: "text-decoration-line:line-through"
-        }
-      ]
-    },
-    underline: {
-      parseDOM: [{ tag: "u" }, { style: "text-decoration:underline" }],
-      toDOM: () => [
-        "span",
-        {
-          style: "text-decoration:underline"
-        }
-      ]
-    },
-    source: {
-      parseDOM: [{ tag: "cite" }],
-      toDOM() {
-        return ["cite", 0];
-      }
-    }
-  }
-};
-
-const allNodes = {
-  ...XpubSchema.nodes,
-  ...tableNodes({
-    tableGroup: "block",
-    cellContent: "block+"
-  })
-};
-
-export default XpubSchema;
diff --git a/wax-prosemirror-schema/src/editoria/EditoriaSchema.js b/wax-prosemirror-schema/src/editoria/EditoriaSchema.js
deleted file mode 100644
index a8411b0c8041fa9d846220dcf9e7896d97d5c41c..0000000000000000000000000000000000000000
--- a/wax-prosemirror-schema/src/editoria/EditoriaSchema.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import nodes from "./nodes";
-import marks from "./marks";
-
-const EditoriaSchema = {
-  nodes,
-  marks
-};
-
-export default EditoriaSchema;
diff --git a/wax-prosemirror-schema/src/editoria/marks.js b/wax-prosemirror-schema/src/editoria/marks.js
deleted file mode 100644
index d5792ded525b9989fdb56bba3ae003ca835e1e99..0000000000000000000000000000000000000000
--- a/wax-prosemirror-schema/src/editoria/marks.js
+++ /dev/null
@@ -1,259 +0,0 @@
-const emDOM = ["em", 0],
-  strongDOM = ["strong", 0],
-  codeDOM = ["code", 0];
-
-const marks = {
-  link: {
-    attrs: {
-      href: { default: null },
-      rel: { default: "" },
-      target: { default: "blank" },
-      title: { default: null }
-    },
-    inclusive: false,
-    parseDOM: [
-      {
-        tag: "a[href]",
-        getAttrs: dom => {
-          const href = dom.getAttribute("href");
-          const target = href && href.indexOf("#") === 0 ? "" : "blank";
-          return {
-            href: dom.getAttribute("href"),
-            title: dom.getAttribute("title"),
-            target
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      return ["a", node.attrs, 0];
-    }
-  },
-  em: {
-    parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
-    toDOM() {
-      return emDOM;
-    }
-  },
-  strong: {
-    parseDOM: [
-      { tag: "strong" },
-      {
-        tag: "b",
-        getAttrs: node => node.style.fontWeight != "normal" && null
-      },
-      {
-        style: "font-weight",
-        getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
-      }
-    ],
-    toDOM() {
-      return strongDOM;
-    }
-  },
-  code: {
-    parseDOM: [{ tag: "code" }],
-    toDOM() {
-      return codeDOM;
-    }
-  },
-  subscript: {
-    excludes: "superscript",
-    parseDOM: [{ tag: "sub" }, { style: "vertical-align=sub" }],
-    toDOM: () => ["sub"]
-  },
-  superscript: {
-    excludes: "subscript",
-    parseDOM: [{ tag: "sup" }, { style: "vertical-align=super" }],
-    toDOM: () => ["sup"]
-  },
-  strikethrough: {
-    parseDOM: [
-      { tag: "strike" },
-      { style: "text-decoration:line-through" },
-      { style: "text-decoration-line:line-through" }
-    ],
-    toDOM: () => [
-      "span",
-      {
-        style: "text-decoration-line:line-through"
-      }
-    ]
-  },
-  underline: {
-    parseDOM: [{ tag: "u" }, { style: "text-decoration:underline" }],
-    toDOM: () => [
-      "span",
-      {
-        style: "text-decoration:underline"
-      }
-    ]
-  },
-  small_caps: {
-    attrs: {
-      class: { default: "small-caps" }
-    },
-    // inclusive: false,
-    parseDOM: [
-      {
-        tag: "span.small-caps",
-        getAttrs(dom) {
-          return { class: dom.getAttribute("class") };
-        }
-      }
-    ],
-    toDOM(node) {
-      return ["span", node.attrs, 0];
-    }
-  },
-  source: {
-    parseDOM: [{ tag: "cite" }],
-    toDOM() {
-      return ["cite", 0];
-    }
-  },
-  insertion: {
-    attrs: {
-      user: {
-        default: 0
-      },
-      username: {
-        default: ""
-      },
-      date: {
-        default: 0
-      },
-      approved: {
-        default: true
-      }
-    },
-    inclusive: false,
-    group: "track",
-    parseDOM: [
-      {
-        tag: "span.insertion",
-        getAttrs(dom) {
-          return {
-            user: parseInt(dom.dataset.user),
-            username: dom.dataset.username,
-            date: parseInt(dom.dataset.date),
-            inline: true,
-            approved: false
-          };
-        }
-      },
-      {
-        tag: "span.approved-insertion",
-        getAttrs(dom) {
-          return {
-            user: parseInt(dom.dataset.user),
-            username: dom.dataset.username,
-            date: parseInt(dom.dataset.date),
-            inline: true,
-            approved: true
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      return [
-        "span",
-        {
-          class: node.attrs.approved
-            ? "approved-insertion"
-            : `insertion user-${node.attrs.user}`,
-          "data-user": node.attrs.user,
-          "data-username": node.attrs.username,
-          "data-date": node.attrs.date
-        }
-      ];
-    }
-  },
-  deletion: {
-    attrs: {
-      user: {
-        default: 0
-      },
-      username: {
-        default: ""
-      },
-      date: {
-        default: 0
-      }
-    },
-    inclusive: false,
-    group: "track",
-    parseDOM: [
-      {
-        tag: "span.deletion",
-        getAttrs(dom) {
-          return {
-            user: parseInt(dom.dataset.user),
-            username: dom.dataset.username,
-            date: parseInt(dom.dataset.date)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      return [
-        "span",
-        {
-          class: `deletion user-${node.attrs.user}`,
-          "data-user": node.attrs.user,
-          "data-username": node.attrs.username,
-          "data-date": node.attrs.date
-        }
-      ];
-    }
-  },
-  format_change: {
-    attrs: {
-      user: {
-        default: 0
-      },
-      username: {
-        default: ""
-      },
-      date: {
-        default: 0
-      },
-      before: {
-        default: []
-      },
-      after: {
-        default: []
-      }
-    },
-    inclusive: false,
-    group: "track",
-    parseDOM: [
-      {
-        tag: "span.format-change",
-        getAttrs(dom) {
-          return {
-            user: parseInt(dom.dataset.user),
-            username: dom.dataset.username,
-            date: parseInt(dom.dataset.date),
-            before: parseFormatList(dom.dataset.before),
-            after: parseFormatList(dom.dataset.after)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      return [
-        "span",
-        {
-          class: `format-change user-${node.attrs.user}`,
-          "data-user": node.attrs.user,
-          "data-username": node.attrs.username,
-          "data-date": node.attrs.date,
-          "data-before": JSON.stringify(node.attrs.before),
-          "data-after": JSON.stringify(node.attrs.after)
-        }
-      ];
-    }
-  }
-};
-export default marks;
diff --git a/wax-prosemirror-schema/src/editoria/nodes.js b/wax-prosemirror-schema/src/editoria/nodes.js
deleted file mode 100644
index ddcecac7a9e41b4f6cc23f9a8d4b05c9977ac3c7..0000000000000000000000000000000000000000
--- a/wax-prosemirror-schema/src/editoria/nodes.js
+++ /dev/null
@@ -1,437 +0,0 @@
-import { parseFormatList, parseTracks, blockLevelToDOM } from "./helpers";
-const pDOM = ["p", 0],
-  brDOM = ["br"],
-  blockquoteDOM = ["blockquote", 0];
-
-const nodes = {
-  doc: {
-    content: "block+"
-  },
-
-  text: {
-    group: "inline"
-  },
-
-  hard_break: {
-    inline: true,
-    group: "inline",
-    selectable: false,
-    parseDOM: [{ tag: "br" }],
-    toDOM() {
-      return brDOM;
-    }
-  },
-  image: {
-    inline: true,
-    attrs: {
-      src: {},
-      alt: { default: null },
-      title: { default: null },
-      track: { default: [] }
-    },
-    group: "inline",
-    draggable: true,
-    parseDOM: [
-      {
-        tag: "img[src]",
-        getAttrs(dom) {
-          return {
-            src: dom.getAttribute("src"),
-            title: dom.getAttribute("title"),
-            track: parseTracks(dom.dataset.track),
-            alt: dom.getAttribute("alt")
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = {};
-      let temp = "";
-      if (node.attrs.track.length) {
-        attrs["data-track"] = JSON.stringify(node.attrs.track);
-      }
-      let { src, alt, title } = node.attrs;
-      return ["img", { src, alt, title }];
-    }
-  },
-  paragraph: {
-    group: "block",
-    content: "inline*",
-    attrs: {
-      class: { default: "paragraph" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.paragraph",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  author: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "author" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.author",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  epigraphProse: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "epigraph-prose" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.epigraph-prose",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  epigraphPoetry: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "epigraph-poetry" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.epigraph-poetry",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  sourceNote: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "source-note" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.source-note",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  paragraphCont: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "paragraph-cont" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.paragraph-cont",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  extractProse: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "extract-prose" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.extract-prose",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  extractPoetry: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "extract-poetry" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.extract-poetry",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  title: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "title" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.title",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  subtitle: {
-    content: "inline*",
-    group: "block",
-    priority: 0,
-    defining: true,
-    attrs: {
-      class: { default: "cst" },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "p.cst",
-        getAttrs(dom) {
-          return {
-            class: dom.getAttribute("class"),
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = blockLevelToDOM(node);
-      return ["p", attrs, 0];
-    }
-  },
-  heading: {
-    attrs: {
-      level: { default: 1 },
-      track: { default: [] }
-    },
-    content: "inline*",
-    group: "block",
-    defining: true,
-    parseDOM: [
-      {
-        tag: "h1",
-        attrs: { level: 1 },
-        getAttrs(dom) {
-          return {
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      },
-      {
-        tag: "h2",
-        attrs: { level: 2 },
-        getAttrs(dom) {
-          return {
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      },
-      {
-        tag: "h3",
-        attrs: { level: 3 },
-        getAttrs(dom) {
-          return {
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = {};
-      if (node.attrs.track.length) {
-        attrs["data-track"] = JSON.stringify(node.attrs.track);
-      }
-      return [`h${node.attrs.level}`, attrs, 0];
-    }
-  },
-  ordered_list: {
-    group: "block",
-    content: "list_item+",
-    attrs: {
-      order: { default: 1 },
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "ol",
-        getAttrs(dom) {
-          return {
-            order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = {};
-      if (node.attrs.order !== 1) {
-        attrs.start = node.attrs.order;
-      }
-      if (node.attrs.track.length) {
-        attrs["data-track"] = JSON.stringify(node.attrs.track);
-      }
-      return ["ol", attrs, 0];
-    }
-  },
-  bullet_list: {
-    group: "block",
-    content: "list_item+",
-    attrs: {
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "ul",
-        getAttrs(dom) {
-          return {
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = {};
-      if (node.attrs.track.length) {
-        attrs["data-track"] = JSON.stringify(node.attrs.track);
-      }
-      return ["ul", attrs, 0];
-    }
-  },
-  list_item: {
-    content: "block+",
-    attrs: {
-      track: { default: [] }
-    },
-    parseDOM: [
-      {
-        tag: "li",
-        getAttrs(dom) {
-          return {
-            track: parseTracks(dom.dataset.track)
-          };
-        }
-      }
-    ],
-    toDOM(node) {
-      const attrs = {};
-      if (node.attrs.track.length) {
-        attrs["data-track"] = JSON.stringify(node.attrs.track);
-      }
-      return ["li", attrs, 0];
-    },
-    defining: true
-  },
-  blockquote: {
-    content: "block+",
-    group: "block",
-    defining: true,
-    parseDOM: [{ tag: "blockquote" }],
-    toDOM() {
-      return blockquoteDOM;
-    }
-  }
-};
-export default nodes;
diff --git a/wax-prosemirror-schema/src/marks/codeMark.js b/wax-prosemirror-schema/src/marks/codeMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..a9e6ab1ef818a09622c2a272826ba30ba38c3e65
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/codeMark.js
@@ -0,0 +1,9 @@
+const code = {
+  parseDOM: { tag: "code" },
+  toDOM(hook, next) {
+    hook.value = ["code", 0];
+    next();
+  }
+};
+
+export default code;
diff --git a/wax-prosemirror-schema/src/marks/emphasisMark.js b/wax-prosemirror-schema/src/marks/emphasisMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e570668cbb7e8478ed00a3d4c1ac19b7e371fda
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/emphasisMark.js
@@ -0,0 +1,9 @@
+const em = {
+  parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
+  toDOM(hook, next) {
+    hook.value = ["em", 0];
+    next();
+  }
+};
+
+export default em;
diff --git a/wax-prosemirror-schema/src/marks/linkMark.js b/wax-prosemirror-schema/src/marks/linkMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..1acb5dcc35216bd25089ebf5d9de8ee164b157eb
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/linkMark.js
@@ -0,0 +1,29 @@
+const link = {
+  attrs: {
+    href: { default: null },
+    rel: { default: "" },
+    target: { default: "blank" },
+    title: { default: null }
+  },
+  inclusive: false,
+  parseDOM: [
+    {
+      tag: "a[href]",
+      getAttrs: dom => {
+        const href = dom.getAttribute("href");
+        const target = href && href.indexOf("#") === 0 ? "" : "blank";
+        return {
+          href: dom.getAttribute("href"),
+          title: dom.getAttribute("title"),
+          target
+        };
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    hook.value = ["a", hook.node.attrs, 0];
+    next();
+  }
+};
+
+export default link;
diff --git a/wax-prosemirror-schema/src/marks/smallcapsMark.js b/wax-prosemirror-schema/src/marks/smallcapsMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..9cb8ea03becb9dc6f5a0ebc0041acffc7a659add
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/smallcapsMark.js
@@ -0,0 +1,20 @@
+const smallcaps = {
+  attrs: {
+    class: { default: "small-caps" }
+  },
+  // inclusive: false,
+  parseDOM: [
+    {
+      tag: "span.small-caps",
+      getAttrs(dom) {
+        return { class: dom.getAttribute("class") };
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    hook.value = ["span", hook.node.attrs, 0];
+    next();
+  }
+};
+
+export default smallcaps;
diff --git a/wax-prosemirror-schema/src/marks/sourceMark.js b/wax-prosemirror-schema/src/marks/sourceMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b87d7b462c8198a44b869292a83c97865cfb324
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/sourceMark.js
@@ -0,0 +1,8 @@
+const source = {
+  parseDOM: [{ tag: "cite" }],
+  toDOM() {
+    return ["cite", 0];
+  }
+};
+
+export default source;
diff --git a/wax-prosemirror-schema/src/marks/strikethroughMark.js b/wax-prosemirror-schema/src/marks/strikethroughMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7d2c692eecbd89773a181070f63e6af903c2a75
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/strikethroughMark.js
@@ -0,0 +1,18 @@
+const strikethrough = {
+  parseDOM: [
+    { tag: "strike" },
+    { style: "text-decoration:line-through" },
+    { style: "text-decoration-line:line-through" }
+  ],
+  toDOM: (hook, next) => {
+    hook.value = [
+      "span",
+      {
+        style: "text-decoration-line:line-through"
+      }
+    ];
+    next();
+  }
+};
+
+export default strikethrough;
diff --git a/wax-prosemirror-schema/src/marks/strongMark.js b/wax-prosemirror-schema/src/marks/strongMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..32b9482a176d9ee2af6e4fcfe5b10b43c2ad06ad
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/strongMark.js
@@ -0,0 +1,19 @@
+const strong = {
+  parseDOM: [
+    { tag: "strong" },
+    {
+      tag: "b",
+      getAttrs: node => node.style.fontWeight != "normal" && null
+    },
+    {
+      style: "font-weight",
+      getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
+    }
+  ],
+  toDOM(hook, next) {
+    hook.value = ["strong", 0];
+    next();
+  }
+};
+
+export default strong;
diff --git a/wax-prosemirror-schema/src/marks/subscriptMark.js b/wax-prosemirror-schema/src/marks/subscriptMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee7d7fc4a48543f2aa23af199cbe4e8531745de3
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/subscriptMark.js
@@ -0,0 +1,10 @@
+const subscript = {
+  excludes: "superscript",
+  parseDOM: [{ tag: "sub" }, { style: "vertical-align=sub" }],
+  toDOM(hook, next) {
+    hook.value = ["sub"];
+    next();
+  }
+};
+
+export default subscript;
diff --git a/wax-prosemirror-schema/src/marks/superscriptMark.js b/wax-prosemirror-schema/src/marks/superscriptMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..4e4bc5328a2d9ad11544b826c9254cff866cb24d
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/superscriptMark.js
@@ -0,0 +1,10 @@
+const superscript = {
+  excludes: "subscript",
+  parseDOM: [{ tag: "sup" }, { style: "vertical-align=super" }],
+  toDOM: (hook, next) => {
+    hook.value = ["sup"];
+    next();
+  }
+};
+
+export default superscript;
diff --git a/wax-prosemirror-schema/src/marks/trackChangesMarks/deletionMark.js b/wax-prosemirror-schema/src/marks/trackChangesMarks/deletionMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..7294dc1fe1344f60bff1c9054ab5f7ec0c5c5304
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/trackChangesMarks/deletionMark.js
@@ -0,0 +1,39 @@
+const deletion = {
+  attrs: {
+    user: {
+      default: 0
+    },
+    username: {
+      default: ""
+    },
+    date: {
+      default: 0
+    }
+  },
+  inclusive: false,
+  group: "track",
+  parseDOM: [
+    {
+      tag: "span.deletion",
+      getAttrs(dom) {
+        return {
+          user: parseInt(dom.dataset.user),
+          username: dom.dataset.username,
+          date: parseInt(dom.dataset.date)
+        };
+      }
+    }
+  ],
+  toDOM(node) {
+    return [
+      "span",
+      {
+        class: `deletion user-${node.attrs.user}`,
+        "data-user": node.attrs.user,
+        "data-username": node.attrs.username,
+        "data-date": node.attrs.date
+      }
+    ];
+  }
+};
+export default deletion;
diff --git a/wax-prosemirror-schema/src/marks/trackChangesMarks/formatChangeMark.js b/wax-prosemirror-schema/src/marks/trackChangesMarks/formatChangeMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..37ceac821b6f8eb05db3a62762b42945b8cb7575
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/trackChangesMarks/formatChangeMark.js
@@ -0,0 +1,50 @@
+const format_change = {
+  attrs: {
+    user: {
+      default: 0
+    },
+    username: {
+      default: ""
+    },
+    date: {
+      default: 0
+    },
+    before: {
+      default: []
+    },
+    after: {
+      default: []
+    }
+  },
+  inclusive: false,
+  group: "track",
+  parseDOM: [
+    {
+      tag: "span.format-change",
+      getAttrs(dom) {
+        return {
+          user: parseInt(dom.dataset.user),
+          username: dom.dataset.username,
+          date: parseInt(dom.dataset.date),
+          before: parseFormatList(dom.dataset.before),
+          after: parseFormatList(dom.dataset.after)
+        };
+      }
+    }
+  ],
+  toDOM(node) {
+    return [
+      "span",
+      {
+        class: `format-change user-${node.attrs.user}`,
+        "data-user": node.attrs.user,
+        "data-username": node.attrs.username,
+        "data-date": node.attrs.date,
+        "data-before": JSON.stringify(node.attrs.before),
+        "data-after": JSON.stringify(node.attrs.after)
+      }
+    ];
+  }
+};
+
+export default format_change;
diff --git a/wax-prosemirror-schema/src/marks/trackChangesMarks/index.js b/wax-prosemirror-schema/src/marks/trackChangesMarks/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..1be38fc68e227dd5b301df09880453d6cde8b02a
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/trackChangesMarks/index.js
@@ -0,0 +1,9 @@
+import insertionMark from "./insertionMark";
+import deletionMark from "./deletionMark";
+import formatChangeMark from "./formatChangeMark";
+
+export default {
+  insertion: insertionMark,
+  deletion: deletionMark,
+  format_change: formatChangeMark
+};
diff --git a/wax-prosemirror-schema/src/marks/trackChangesMarks/insertionMark.js b/wax-prosemirror-schema/src/marks/trackChangesMarks/insertionMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..365ccc3c52806b747bad3fe069aa6593c5c59dd5
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/trackChangesMarks/insertionMark.js
@@ -0,0 +1,59 @@
+const insertion = {
+  attrs: {
+    user: {
+      default: 0
+    },
+    username: {
+      default: ""
+    },
+    date: {
+      default: 0
+    },
+    approved: {
+      default: true
+    }
+  },
+  inclusive: false,
+  group: "track",
+  parseDOM: [
+    {
+      tag: "span.insertion",
+      getAttrs(dom) {
+        return {
+          user: parseInt(dom.dataset.user),
+          username: dom.dataset.username,
+          date: parseInt(dom.dataset.date),
+          inline: true,
+          approved: false
+        };
+      }
+    },
+    {
+      tag: "span.approved-insertion",
+      getAttrs(dom) {
+        return {
+          user: parseInt(dom.dataset.user),
+          username: dom.dataset.username,
+          date: parseInt(dom.dataset.date),
+          inline: true,
+          approved: true
+        };
+      }
+    }
+  ],
+  toDOM(node) {
+    return [
+      "span",
+      {
+        class: node.attrs.approved
+          ? "approved-insertion"
+          : `insertion user-${node.attrs.user}`,
+        "data-user": node.attrs.user,
+        "data-username": node.attrs.username,
+        "data-date": node.attrs.date
+      }
+    ];
+  }
+};
+
+export default insertion;
diff --git a/wax-prosemirror-schema/src/marks/underlineMark.js b/wax-prosemirror-schema/src/marks/underlineMark.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe7ac335ac85b85691fe59a5b55bb5104af0612e
--- /dev/null
+++ b/wax-prosemirror-schema/src/marks/underlineMark.js
@@ -0,0 +1,14 @@
+const underline = {
+  parseDOM: [{ tag: "u" }, { style: "text-decoration:underline" }],
+  toDOM: (hook, next) => {
+    hook.value = [
+      "span",
+      {
+        style: "text-decoration:underline"
+      }
+    ];
+    next();
+  }
+};
+
+export default underline;
diff --git a/wax-prosemirror-schema/src/nodes/authorNode.js b/wax-prosemirror-schema/src/nodes/authorNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b954aac40e5d511785831a1b592fd3cf4a7d982
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/authorNode.js
@@ -0,0 +1,27 @@
+const author = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "author" }
+  },
+  parseDOM: [
+    {
+      tag: "p.author",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class")
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = { class: hook.node.attrs.class };
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default author;
diff --git a/wax-prosemirror-schema/src/nodes/blockQuoteNode.js b/wax-prosemirror-schema/src/nodes/blockQuoteNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5ac23dcbdcd6c3fa232c41d5edd8bccaacfce3c
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/blockQuoteNode.js
@@ -0,0 +1,13 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+
+const blockquote = {
+  content: "block+",
+  group: "block",
+  defining: true,
+  parseDOM: [{ tag: "blockquote" }],
+  toDOM() {
+    return ["blockquote", 0];
+  }
+};
+
+export default blockquote;
diff --git a/wax-prosemirror-schema/src/nodes/bulletListNode.js b/wax-prosemirror-schema/src/nodes/bulletListNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..2fd0744dc914077bc7570242392f9022e5642cc1
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/bulletListNode.js
@@ -0,0 +1,28 @@
+const bulletlist = {
+  group: "block",
+  content: "list_item+",
+  attrs: {
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "ul",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = {};
+    if (hook.node.attrs.track.length) {
+      attrs["data-track"] = JSON.stringify(hook.node.attrs.track);
+    }
+    hook.value = ["ul", attrs, 0];
+    next();
+  }
+};
+
+export default bulletlist;
diff --git a/wax-prosemirror-schema/src/nodes/epigraphPoetryNode.js b/wax-prosemirror-schema/src/nodes/epigraphPoetryNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd5fbc567bb5aca87ed4db50420a1cc898f40e1c
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/epigraphPoetryNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const epigraphPoetry = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "epigraph-poetry" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.epigraph-poetry",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default epigraphPoetry;
diff --git a/wax-prosemirror-schema/src/nodes/epigraphProseNode.js b/wax-prosemirror-schema/src/nodes/epigraphProseNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..bde074f94f0458e18c35824a5f077693181683ea
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/epigraphProseNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const epigraphProse = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "epigraph-prose" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.epigraph-prose",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default epigraphProse;
diff --git a/wax-prosemirror-schema/src/nodes/extractPoetryNode.js b/wax-prosemirror-schema/src/nodes/extractPoetryNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..bf4499c03fd41d297c9efd90fc19948cb5bc9acc
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/extractPoetryNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const extractPoetry = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "extract-poetry" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.extract-poetry",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default extractPoetry;
diff --git a/wax-prosemirror-schema/src/nodes/extractProseNode.js b/wax-prosemirror-schema/src/nodes/extractProseNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0c52b6044fe7ba3a4783e67e09f27403945f450
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/extractProseNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const extractProse = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "extract-prose" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.extract-prose",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default extractProse;
diff --git a/wax-prosemirror-schema/src/nodes/headingNode.js b/wax-prosemirror-schema/src/nodes/headingNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..85993a2daa0512dddce4d84145ef218d14eae526
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/headingNode.js
@@ -0,0 +1,52 @@
+import { parseTracks } from "./helpers";
+const heading = {
+  attrs: {
+    level: { default: 1 },
+    track: { default: [] }
+  },
+  content: "inline*",
+  group: "block",
+  defining: true,
+  parseDOM: [
+    {
+      tag: "h1",
+      attrs: { level: 1 },
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    },
+    {
+      tag: "h2",
+      attrs: { level: 2 },
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    },
+    {
+      tag: "h3",
+      attrs: { level: 3 },
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = {};
+    if (hook.node.attrs.track.length) {
+      attrs["data-track"] = JSON.stringify(hook.node.attrs.track);
+    }
+    hook.value = [`h${hook.node.attrs.level}`, attrs, 0];
+    next();
+  }
+};
+
+export default heading;
diff --git a/wax-prosemirror-schema/src/editoria/helpers.js b/wax-prosemirror-schema/src/nodes/helpers.js
similarity index 100%
rename from wax-prosemirror-schema/src/editoria/helpers.js
rename to wax-prosemirror-schema/src/nodes/helpers.js
diff --git a/wax-prosemirror-schema/src/nodes/imageNode.js b/wax-prosemirror-schema/src/nodes/imageNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ac1badd366fb0a74a50e0801b6015b0b635565c
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/imageNode.js
@@ -0,0 +1,37 @@
+const image = {
+  inline: true,
+  attrs: {
+    src: {},
+    alt: { default: null },
+    title: { default: null },
+    track: { default: [] }
+  },
+  group: "inline",
+  draggable: true,
+  parseDOM: [
+    {
+      tag: "img[src]",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          src: hook.dom.getAttribute("src"),
+          title: hook.dom.getAttribute("title"),
+          // track: parseTracks(hook.dom.dataset.track),
+          alt: hook.dom.getAttribute("alt")
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = {};
+    let temp = "";
+    // if (hook.node.attrs.track.length) {
+    //   // attrs["data-track"] = JSON.stringify(hook.node.attrs.track);
+    // }
+    let { src, alt, title } = hook.node.attrs;
+    hook.value = ["img", { src, alt, title }];
+    next();
+  }
+};
+
+export default image;
diff --git a/wax-prosemirror-schema/src/nodes/listItemNode.js b/wax-prosemirror-schema/src/nodes/listItemNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..a91948c24d2da91d1a95727738f69eb8de106a3e
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/listItemNode.js
@@ -0,0 +1,28 @@
+const list_item = {
+  content: "block+",
+  attrs: {
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "li",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = {};
+    if (hook.node.attrs.track.length) {
+      attrs["data-track"] = JSON.stringify(hook.node.attrs.track);
+    }
+    hook.value = ["li", attrs, 0];
+    next();
+  },
+  defining: true
+};
+
+export default list_item;
diff --git a/wax-prosemirror-schema/src/nodes/orderedListNode.js b/wax-prosemirror-schema/src/nodes/orderedListNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..3759361246b57115e4ad1fe5b356956d9000bb01
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/orderedListNode.js
@@ -0,0 +1,35 @@
+const orderedlist = {
+  group: "block",
+  content: "list_item+",
+  attrs: {
+    order: { default: 1 },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "ol",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          order: hook.dom.hasAttribute("start")
+            ? +hook.dom.getAttribute("start")
+            : 1,
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = {};
+    if (hook.node.attrs.order !== 1) {
+      attrs.start = hook.node.attrs.order;
+    }
+    if (hook.node.attrs.track.length) {
+      attrs["data-track"] = JSON.stringify(hook.node.attrs.track);
+    }
+    hook.value = ["ol", attrs, 0];
+    next();
+  }
+};
+
+export default orderedlist;
diff --git a/wax-prosemirror-schema/src/nodes/paragraphContNode.js b/wax-prosemirror-schema/src/nodes/paragraphContNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..5dcdb0f4ec540e1cce7f38af5c4caa91eb2e243f
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/paragraphContNode.js
@@ -0,0 +1,31 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+
+const paragraphCont = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "paragraph-cont" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.paragraph-cont",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default paragraphCont;
diff --git a/wax-prosemirror-schema/src/nodes/sourceNoteNode.js b/wax-prosemirror-schema/src/nodes/sourceNoteNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..4b0298a249117cb3969574e9155ecfd8a4cfec4b
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/sourceNoteNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const sourceNote = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "source-note" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.source-note",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: hook.dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default sourceNote;
diff --git a/wax-prosemirror-schema/src/nodes/subTitleNode.js b/wax-prosemirror-schema/src/nodes/subTitleNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..85b59a8687aa6caf51fdbae6ee96fc17fba9a77f
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/subTitleNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const subtitle = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "cst" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.cst",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default subtitle;
diff --git a/wax-prosemirror-schema/src/nodes/titleNode.js b/wax-prosemirror-schema/src/nodes/titleNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7c2b1bf0bf5bbe25b9a88eb15796d51b106db74
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/titleNode.js
@@ -0,0 +1,30 @@
+import { parseTracks, blockLevelToDOM } from "./helpers";
+const title = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    class: { default: "title" },
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.title",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          class: dom.getAttribute("class"),
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    const attrs = blockLevelToDOM(hook.node);
+    hook.value = ["p", attrs, 0];
+    next();
+  }
+};
+
+export default title;
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/authorTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/authorTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..3cc28a161d15d4b014da252d0d51bf84e3d22c33
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/trackChangesNodes/authorTrackNode.js
@@ -0,0 +1,29 @@
+import { parseTracks } from "../helpers";
+const author = {
+  content: "inline*",
+  group: "block",
+  priority: 0,
+  defining: true,
+  attrs: {
+    track: { default: [] }
+  },
+  parseDOM: [
+    {
+      tag: "p.author",
+      getAttrs(hook, next) {
+        Object.assign(hook, {
+          track: parseTracks(hook.dom.dataset.track)
+        });
+        next();
+      }
+    }
+  ],
+  toDOM(hook, next) {
+    Object.assign(hook.value[1], {
+      "data-track": JSON.stringify(hook.node.attrs.track)
+    });
+    next();
+  }
+};
+
+export default author;
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/bulletListTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/bulletListTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/epigraphPoetryTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/epigraphPoetryTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/epigraphProseTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/epigraphProseTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/extractPoetryTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/extractPoetryTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/extractProseTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/extractProseTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/headingTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/headingTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/imageTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/imageTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/index.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..907b4febb1fbf2857cd2d6cadd0320cfff81dc75
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/trackChangesNodes/index.js
@@ -0,0 +1,32 @@
+import paragraphTrackNode from "./paragraphTrackNode";
+import authorTrackNode from "./authorTrackNode";
+import titleTrackNode from "./titleTrackNode";
+import subTitleTrackNode from "./subTitleTrackNode";
+import epigraphProseTrackNode from "./epigraphProseTrackNode";
+import epigraphPoetryTrackNode from "./epigraphPoetryTrackNode";
+import headingTrackNode from "./headingTrackNode";
+import paragraphContTrackNode from "./paragraphContTrackNode";
+import extractProseTrackNode from "./extractProseTrackNode";
+import extractPoetryTrackNode from "./extractPoetryTrackNode";
+import sourceNoteTrackNode from "./sourceNoteTrackNode";
+import bulletListTrackNode from "./bulletListTrackNode";
+import orderedListTrackNode from "./orderedListTrackNode";
+import listItemTrackNode from "./listItemTrackNode";
+import imageTrackNode from "./imageTrackNode";
+
+export default {
+  // paragraph: paragraphTrackNode,
+  author: authorTrackNode
+  // title: titleTrackNode,
+  //subtitle: subTitleTrackNode,
+  //epigraphProse: epigraphProseTrackNode,
+  //epigraphPoetry: epigraphPoetryTrackNode,
+  // paragraphCont: paragraphContTrackNode,
+  // extractProse: extractProseTrackNode,
+  // extractPoetry: extractPoetryTrackNode,
+  // sourceNote: sourceNoteTrackNode,
+  // bulletlist: bulletListTrackNode,
+  // orderedlist: orderedListTrackNode,
+  // list_item: listItemTrackNode,
+  // image: imageTrackNode
+};
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/listItemTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/listItemTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/orderedListTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/orderedListTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/paragraphContTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/paragraphContTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/paragraphTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/paragraphTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..ebdb44e7125eaaa49518440cbbe8d38de40b50e5
--- /dev/null
+++ b/wax-prosemirror-schema/src/nodes/trackChangesNodes/paragraphTrackNode.js
@@ -0,0 +1,26 @@
+import { parseTracks } from "../helpers";
+
+const paragraph = {
+  group: "block",
+  content: "inline*",
+  attrs: {
+    track: { default: [] }
+  },
+  parseDOM: {
+    tag: "p.paragraph",
+    getAttrs(hook, next) {
+      Object.assign(hook, {
+        track: parseTracks(hook.dom.dataset.track)
+      });
+      next();
+    }
+  },
+  toDOM(hook, next) {
+    Object.assign(hook.value[1], {
+      "data-track": JSON.stringify(hook.node.attrs.track)
+    });
+    next();
+  }
+};
+
+export default paragraph;
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/sourceNoteTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/sourceNoteTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/subTitleTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/subTitleTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-schema/src/nodes/trackChangesNodes/titleTrackNode.js b/wax-prosemirror-schema/src/nodes/trackChangesNodes/titleTrackNode.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/wax-prosemirror-services/.gitignore b/wax-prosemirror-services/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..7a2f31d8e3f6bfb63391deb56b2acc49193477a1
--- /dev/null
+++ b/wax-prosemirror-services/.gitignore
@@ -0,0 +1,21 @@
+# dependencies
+/node_modules
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+yarn.lock
+package-lock.json
diff --git a/wax-prosemirror-services/index.js b/wax-prosemirror-services/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..d16ab4d6cb1784c1aac4624b104d98b35d44f434
--- /dev/null
+++ b/wax-prosemirror-services/index.js
@@ -0,0 +1,36 @@
+export { default as MenuService } from "./src/MenuService/MenuService";
+export { default as LinkService } from "./src/LinkService/LinkService";
+export { default as PlaceholderService } from "./src/PlaceholderService/PlaceholderService";
+export { default as ImageService } from "./src/ImageService/ImageService";
+export { default as RulesService } from "./src/RulesService/RulesService";
+export { default as SchemaService } from "./src/SchemaService/SchemaService";
+
+export { default as ShortCutsService } from "./src/ShortCutsService/ShortCutsService";
+
+export { default as OverlayService } from "./src/OverlayService/OverlayService";
+export { default as Tool } from "./src/lib/Tools";
+export {
+  default as TrackChangeService
+} from "./src/TrackChangeService/TrackChangeService";
+
+/*
+All Elements services
+*/
+export { default as BaseService } from "./src/BaseService/BaseService";
+export { default as InlineAnnotationsService } from "./src/InlineAnnotations/InlineAnnotationsService";
+export { default as ListsService } from "./src/ListsService/ListsService";
+export { default as TablesService } from "./src/TablesService/TablesService";
+export { default as TextBlockLevelService } from "./src/TextBlockLevel/TextBlockLevelService";
+export { default as DisplayBlockLevelService } from "./src/DisplayBlockLevel/DisplayBlockLevelService";
+
+/*
+ToolGroups
+*/
+export { default as BaseToolGroupService } from "./src/WaxToolGroups/BaseToolGroupService/BaseToolGroupService";
+export { default as AnnotationToolGroupService } from "./src/WaxToolGroups/AnnotationToolGroupService/AnnotationToolGroupService";
+export { default as ListToolGroupService } from "./src/WaxToolGroups/ListToolGroupService/ListToolGroupService";
+export { default as ImageToolGroupService } from "./src/WaxToolGroups/ImageToolGroupService/ImageToolGroupService";
+export { default as TableToolGroupService } from "./src/WaxToolGroups/TableToolGroupService/TableToolGroupService";
+export { default as DisplayToolGroupService } from "./src/WaxToolGroups/DisplayToolGroupService/DisplayToolGroupService";
+export { default as TextToolGroupService } from "./src/WaxToolGroups/TextToolGroupService/TextToolGroupService";
+export { default as NoteService } from "./src/NoteService/NoteService";
diff --git a/wax-prosemirror-services/package.json b/wax-prosemirror-services/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0129da92cec6b86aeb4cdf66329ddd725aaa0da
--- /dev/null
+++ b/wax-prosemirror-services/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "wax-prosemirror-services",
+  "author": "Collaborative Knowledge Foundation",
+  "version": "0.0.3",
+  "description": "Wax prosemirror services",
+  "license": "MIT",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "dependencies": {
+    "inversify": "^5.0.1",
+    "inversify-inject-decorators": "^3.1.0",
+    "prosemirror-state": "^1.2.2",
+    "prosemirror-view": "^1.13.1",
+    "wax-prosemirror-components": "^0.0.3",
+    "wax-prosemirror-core": "^0.0.3",
+    "wax-prosemirror-layouts": "^0.0.3",
+    "styled-components": "^4.2.0"
+  }
+}
diff --git a/wax-prosemirror-services/src/BaseService/BaseService.js b/wax-prosemirror-services/src/BaseService/BaseService.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5f327077e53da733d0b27e1c0a033afbcecfa9c
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/BaseService.js
@@ -0,0 +1,10 @@
+import BaseServices from "./index";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class BaseService extends Service {
+  register() {
+    this.config.pushToArray("services", BaseServices);
+  }
+}
+
+export default BaseService;
diff --git a/wax-prosemirror-services/src/BaseService/RedoService/Redo.js b/wax-prosemirror-services/src/BaseService/RedoService/Redo.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc9ddc249c9c31184d3b2b97f56dfd70ef2d9053
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/RedoService/Redo.js
@@ -0,0 +1,18 @@
+import { redo } from "prosemirror-history";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Redo extends Tools {
+  title = "Redo last undone change";
+  content = icons.redo;
+
+  get run() {
+    return redo;
+  }
+
+  get enable() {
+    return redo;
+  }
+}
diff --git a/wax-prosemirror-services/src/BaseService/RedoService/RedoService.js b/wax-prosemirror-services/src/BaseService/RedoService/RedoService.js
new file mode 100644
index 0000000000000000000000000000000000000000..fcd403e46d542a94eb845a84c8f842d3b41d0ee3
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/RedoService/RedoService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Redo from "./Redo";
+
+class RedoService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Redo").to(Redo);
+  }
+}
+
+export default RedoService;
diff --git a/wax-prosemirror-services/src/BaseService/SaveService/Save.js b/wax-prosemirror-services/src/BaseService/SaveService/Save.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d43004adf21cbb16378d24b8a9cc6dff0a19770
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/SaveService/Save.js
@@ -0,0 +1,13 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Save extends Tools {
+  title = "Save changes";
+  content = icons.save;
+
+  get run() {}
+
+  get enable() {}
+}
diff --git a/wax-prosemirror-services/src/BaseService/SaveService/SaveService.js b/wax-prosemirror-services/src/BaseService/SaveService/SaveService.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ed2c5bef669cd195ca3f9fa1f02f3846278b649
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/SaveService/SaveService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Save from "./Save";
+
+class SaveService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Save").to(Save);
+  }
+}
+
+export default SaveService;
diff --git a/wax-prosemirror-services/src/BaseService/UndoService/Undo.js b/wax-prosemirror-services/src/BaseService/UndoService/Undo.js
new file mode 100644
index 0000000000000000000000000000000000000000..27027af0f0a729af09457f8c6a1c5141d58526d5
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/UndoService/Undo.js
@@ -0,0 +1,18 @@
+import { undo } from "prosemirror-history";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Undo extends Tools {
+  title = "Undo last change";
+  content = icons.undo;
+
+  get run() {
+    return undo;
+  }
+
+  get enable() {
+    return undo;
+  }
+}
diff --git a/wax-prosemirror-services/src/BaseService/UndoService/UndoService.js b/wax-prosemirror-services/src/BaseService/UndoService/UndoService.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a52e780a1104c6f9db13473a2f17864157b9b14
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/UndoService/UndoService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Undo from "./Undo";
+
+class UndoService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Undo").to(Undo);
+  }
+}
+
+export default UndoService;
diff --git a/wax-prosemirror-services/src/BaseService/index.js b/wax-prosemirror-services/src/BaseService/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac21c7dee1b100298434bdca50e12e2212341275
--- /dev/null
+++ b/wax-prosemirror-services/src/BaseService/index.js
@@ -0,0 +1,5 @@
+import UndoService from "./UndoService/UndoService";
+import RedoService from "./RedoService/RedoService";
+import SaveService from "./SaveService/SaveService";
+
+export default [new UndoService(), new RedoService()];
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/AuthorService/Author.js b/wax-prosemirror-services/src/DisplayBlockLevel/AuthorService/Author.js
new file mode 100644
index 0000000000000000000000000000000000000000..6be138dd84d3867dcf35a138f1efc71f55025856
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/AuthorService/Author.js
@@ -0,0 +1,21 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class Author extends Tools {
+  title = "Change to Author";
+  content = "Author";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.author)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.author)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/AuthorService/AuthorService.js b/wax-prosemirror-services/src/DisplayBlockLevel/AuthorService/AuthorService.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7a259badac013bdc51f3573abfe954fe7c91c7a
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/AuthorService/AuthorService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { authorNode } from "wax-prosemirror-schema";
+import Author from "./Author";
+
+class AuthorService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Author").to(Author);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        author: authorNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default AuthorService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/DisplayBlockLevelService.js b/wax-prosemirror-services/src/DisplayBlockLevel/DisplayBlockLevelService.js
new file mode 100644
index 0000000000000000000000000000000000000000..74050fa274fbc670e270dfd2cf058c8993ddca60
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/DisplayBlockLevelService.js
@@ -0,0 +1,10 @@
+import DisplayServices from "./index";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class DisplayBlockLevelService extends Service {
+  register() {
+    this.config.pushToArray("services", DisplayServices);
+  }
+}
+
+export default DisplayBlockLevelService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphPoetryService/EpigraphPoetry.js b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphPoetryService/EpigraphPoetry.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3d63856ad2c61fd6adf2e4ed0d59a62ccb49597
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphPoetryService/EpigraphPoetry.js
@@ -0,0 +1,21 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class EpigraphPoetry extends Tools {
+  title = "Change to Epigraph Poetry";
+  content = "Epigraph Poetry";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.epigraphPoetry)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.epigraphPoetry)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphPoetryService/EpigraphPoetryService.js b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphPoetryService/EpigraphPoetryService.js
new file mode 100644
index 0000000000000000000000000000000000000000..8827f9725db1216bcd328f600eb65ae0207a22c5
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphPoetryService/EpigraphPoetryService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { epigraphPoetryNode } from "wax-prosemirror-schema";
+import EpigraphPoetry from "./EpigraphPoetry";
+
+class EpigraphPoetryService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("EpigraphPoetry").to(EpigraphPoetry);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        epigraphPoetry: epigraphPoetryNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default EpigraphPoetryService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphProseService/EpigraphProse.js b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphProseService/EpigraphProse.js
new file mode 100644
index 0000000000000000000000000000000000000000..8347f6bcba19e6d9775570556621f413bf7bdb68
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphProseService/EpigraphProse.js
@@ -0,0 +1,21 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class EpigraphProse extends Tools {
+  title = "Change to Epigraph Prose";
+  content = "Epigraph Prose";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.epigraphProse)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.epigraphProse)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphProseService/EpigraphProseService.js b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphProseService/EpigraphProseService.js
new file mode 100644
index 0000000000000000000000000000000000000000..e399616db725e33e06bcea4ddfb2010ba882c0c6
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/EpigraphProseService/EpigraphProseService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { epigraphProseNode } from "wax-prosemirror-schema";
+import EpigraphProse from "./EpigraphProse";
+
+class EpigraphProseService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("EpigraphProse").to(EpigraphProse);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        epigraphProse: epigraphProseNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default EpigraphProseService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading1.js b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading1.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ad2dc6815cae6e8a5f17475c58c0cbfefdde9df
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading1.js
@@ -0,0 +1,27 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class Heading1 extends Tools {
+  title = "Change to heading level 1";
+  content = "Heading 1";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.heading, { level: 1 })(
+        state,
+        dispatch
+      );
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.heading, {
+        level: 1,
+        track: []
+      })(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading2.js b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading2.js
new file mode 100644
index 0000000000000000000000000000000000000000..80a7b88e85be051e845f935af071e30ea4d22e20
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading2.js
@@ -0,0 +1,27 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class Heading2 extends Tools {
+  title = "Change to heading level 2";
+  content = "Heading 2";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.heading, { level: 2 })(
+        state,
+        dispatch
+      );
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.heading, {
+        level: 2,
+        track: []
+      })(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading3.js b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading3.js
new file mode 100644
index 0000000000000000000000000000000000000000..8163289fb5ed31ef2f65eea71069b16779202170
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/Heading3.js
@@ -0,0 +1,27 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class Heading3 extends Tools {
+  title = "Change to heading level 3";
+  content = "Heading 3";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.heading, { level: 3 })(
+        state,
+        dispatch
+      );
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.heading, {
+        level: 3,
+        track: []
+      })(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/HeadingService.js b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/HeadingService.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a2e6cc71a3cc8576783a17b4a73818110fcd3de
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/HeadingService/HeadingService.js
@@ -0,0 +1,24 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { headingNode } from "wax-prosemirror-schema";
+import Heading1 from "./Heading1";
+import Heading2 from "./Heading2";
+import Heading3 from "./Heading3";
+
+class HeadingService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Heading1").to(Heading1);
+    this.container.bind("Heading2").to(Heading2);
+    this.container.bind("Heading3").to(Heading3);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        heading: headingNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default HeadingService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/SubTitleService/SubTitle.js b/wax-prosemirror-services/src/DisplayBlockLevel/SubTitleService/SubTitle.js
new file mode 100644
index 0000000000000000000000000000000000000000..caac1427b53f761996822dabc87b6173bcf65b36
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/SubTitleService/SubTitle.js
@@ -0,0 +1,21 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class SubTitle extends Tools {
+  title = "Change to Subtitle";
+  content = "Subtitle";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.subtitle)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.subtitle)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/SubTitleService/SubTitleService.js b/wax-prosemirror-services/src/DisplayBlockLevel/SubTitleService/SubTitleService.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa825e2ed4a0105d37e8f4aa907a28e85bcf3912
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/SubTitleService/SubTitleService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { subTitleNode } from "wax-prosemirror-schema";
+import SubTitle from "./SubTitle";
+
+class SubTitleService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("SubTitle").to(SubTitle);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        subtitle: subTitleNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default SubTitleService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/TitleService/Title.js b/wax-prosemirror-services/src/DisplayBlockLevel/TitleService/Title.js
new file mode 100644
index 0000000000000000000000000000000000000000..94c85205fdefdce0793fe1be02d8c14364ea7fee
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/TitleService/Title.js
@@ -0,0 +1,22 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+import { blockActive } from "../../lib/Utils";
+
+@injectable()
+export default class Title extends Tools {
+  title = "Change to Title";
+  content = "Title";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.title)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.title)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/TitleService/TitleService.js b/wax-prosemirror-services/src/DisplayBlockLevel/TitleService/TitleService.js
new file mode 100644
index 0000000000000000000000000000000000000000..05221017b16087b42854ac654e5d10bdcc42976d
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/TitleService/TitleService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { titleNode } from "wax-prosemirror-schema";
+import Title from "./Title";
+
+class TitleService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Title").to(Title);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        title: titleNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default TitleService;
diff --git a/wax-prosemirror-services/src/DisplayBlockLevel/index.js b/wax-prosemirror-services/src/DisplayBlockLevel/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..847094daf61e09914336ed0e5b4bf9886107c5c7
--- /dev/null
+++ b/wax-prosemirror-services/src/DisplayBlockLevel/index.js
@@ -0,0 +1,15 @@
+import AuthorService from "./AuthorService/AuthorService";
+import EpigraphPoetryService from "./EpigraphPoetryService/EpigraphPoetryService";
+import EpigraphProseService from "./EpigraphProseService/EpigraphProseService";
+import HeadingService from "./HeadingService/HeadingService";
+import SubTitleService from "./SubTitleService/SubTitleService";
+import TitleService from "./TitleService/TitleService";
+
+export default [
+  new AuthorService(),
+  new EpigraphProseService(),
+  new EpigraphPoetryService(),
+  new HeadingService(),
+  new SubTitleService(),
+  new TitleService()
+];
diff --git a/wax-prosemirror-services/src/ImageService/Image.js b/wax-prosemirror-services/src/ImageService/Image.js
new file mode 100644
index 0000000000000000000000000000000000000000..41d4a1ba69a5640f492281abc548e89009bc2c8d
--- /dev/null
+++ b/wax-prosemirror-services/src/ImageService/Image.js
@@ -0,0 +1,36 @@
+import React from "react";
+import { v4 as uuid } from "uuid";
+import { isEmpty } from "lodash";
+import { injectable } from "inversify";
+import { icons, ImageUpload } from "wax-prosemirror-components";
+import Tools from "../lib/Tools";
+import { canInsert } from "../lib/Utils";
+import fileUpload from "./fileUpload";
+
+@injectable()
+export default class Image extends Tools {
+  title = "Insert image";
+  content = icons.image;
+
+  get run() {
+    return () => true;
+  }
+
+  get enable() {
+    return state => {
+      return canInsert(state.config.schema.nodes.image)(state);
+    };
+  }
+
+  renderTool(view) {
+    if (isEmpty(view)) return null;
+    const upload = fileUpload(
+      view,
+      this.config.get("fileUpload"),
+      this.pmplugins.get("imagePlaceHolder")
+    );
+    return this._isEnabled ? (
+      <ImageUpload key={uuid()} item={this.toJSON()} fileUpload={upload} />
+    ) : null;
+  }
+}
diff --git a/wax-prosemirror-services/src/ImageService/ImageService.js b/wax-prosemirror-services/src/ImageService/ImageService.js
new file mode 100644
index 0000000000000000000000000000000000000000..efa983a1d4eb6ee7c2cbba67086d018cf4cfa882
--- /dev/null
+++ b/wax-prosemirror-services/src/ImageService/ImageService.js
@@ -0,0 +1,18 @@
+import Image from "./Image";
+import { imageNode } from "wax-prosemirror-schema";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+export default class ImageService extends Service {
+  name = "ImageService";
+
+  register() {
+    this.container.bind("Image").to(Image);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        image: imageNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
diff --git a/wax-prosemirror-services/src/ImageService/fileUpload.js b/wax-prosemirror-services/src/ImageService/fileUpload.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa33a6a9037112a8203bb4ccfe77dc8badb4e496
--- /dev/null
+++ b/wax-prosemirror-services/src/ImageService/fileUpload.js
@@ -0,0 +1,49 @@
+const findPlaceholder = (state, id, placeholderPlugin) => {
+  const decos = placeholderPlugin.getState(state);
+  const found = decos.find(null, null, spec => spec.id === id);
+  return found.length ? found[0].from : null;
+};
+
+export default (view, fileUpload, placeholderPlugin) => file => {
+  const { state } = view;
+
+  // A fresh object to act as the ID for this upload
+  const id = {};
+
+  // Replace the selection with a placeholder
+  const { tr } = state;
+  if (!tr.selection.empty) tr.deleteSelection();
+
+  tr.setMeta(placeholderPlugin, {
+    add: { id, pos: tr.selection.from }
+  });
+
+  view.dispatch(tr);
+  fileUpload(file).then(
+    url => {
+      const pos = findPlaceholder(view.state, id, placeholderPlugin);
+      // If the content around the placeholder has been deleted, drop
+      // the image
+      if (pos == null) {
+        return;
+      }
+      // Otherwise, insert it at the placeholder's position, and remove
+      // the placeholder
+      view.dispatch(
+        state.tr
+          .replaceWith(
+            pos,
+            pos,
+            view.state.schema.nodes.image.create({
+              src: url
+            })
+          )
+          .setMeta(placeholderPlugin, { remove: { id } })
+      );
+    },
+    () => {
+      // On failure, just clean up the placeholder
+      view.dispatch(tr.setMeta(placeholderPlugin, { remove: { id } }));
+    }
+  );
+};
diff --git a/wax-prosemirror-services/src/InlineAnnotations/CodeService/Code.js b/wax-prosemirror-services/src/InlineAnnotations/CodeService/Code.js
new file mode 100644
index 0000000000000000000000000000000000000000..61887249a4c332293482402b79f9609392391ce7
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/CodeService/Code.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Code extends Tools {
+  title = "Toggle code";
+  content = icons.code;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.code)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.code)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/CodeService/CodeService.js b/wax-prosemirror-services/src/InlineAnnotations/CodeService/CodeService.js
new file mode 100644
index 0000000000000000000000000000000000000000..c3e5baa8509cf643f6a23559618b8b93d94a360a
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/CodeService/CodeService.js
@@ -0,0 +1,24 @@
+import { toggleMark } from "prosemirror-commands";
+import Service from "wax-prosemirror-core/src/services/Service";
+import { codeMark } from "wax-prosemirror-schema";
+import Code from "./Code";
+
+class CodeService extends Service {
+  boot() {
+    const shortCuts = this.container.get("ShortCuts");
+    shortCuts.addShortCut({ "Mod-`": toggleMark(this.schema.marks.code) });
+  }
+
+  register() {
+    this.container.bind("Code").to(Code);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        code: codeMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default CodeService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/EmphasisService/Emphasis.js b/wax-prosemirror-services/src/InlineAnnotations/EmphasisService/Emphasis.js
new file mode 100644
index 0000000000000000000000000000000000000000..21f977f7afa47e192c485d870769704b00fd18b9
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/EmphasisService/Emphasis.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Emphasis extends Tools {
+  title = "Toggle emphasis";
+  content = icons.em;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.em)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.em)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/EmphasisService/EmphasisService.js b/wax-prosemirror-services/src/InlineAnnotations/EmphasisService/EmphasisService.js
new file mode 100644
index 0000000000000000000000000000000000000000..846d341b64690650a538ab4eccfcbe821bf97e6d
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/EmphasisService/EmphasisService.js
@@ -0,0 +1,24 @@
+import { toggleMark } from "prosemirror-commands";
+import Service from "wax-prosemirror-core/src/services/Service";
+import { emphasisMark } from "wax-prosemirror-schema";
+import Emphasis from "./Emphasis";
+
+class EmphasisService extends Service {
+  boot() {
+    const shortCuts = this.container.get("ShortCuts");
+    shortCuts.addShortCut({ "Mod-i": toggleMark(this.schema.marks.em) });
+  }
+
+  register() {
+    this.container.bind("Emphasis").to(Emphasis);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        em: emphasisMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default EmphasisService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/InlineAnnotationsService.js b/wax-prosemirror-services/src/InlineAnnotations/InlineAnnotationsService.js
new file mode 100644
index 0000000000000000000000000000000000000000..7dde0d0c21e3dbb75b6c841ae09a4a79e5f93e92
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/InlineAnnotationsService.js
@@ -0,0 +1,8 @@
+import InlineServices from "./index";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class InlineAnnotationsService extends Service {
+  dependencies = InlineServices;
+}
+
+export default InlineAnnotationsService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/SmallCapsService/SmallCaps.js b/wax-prosemirror-services/src/InlineAnnotations/SmallCapsService/SmallCaps.js
new file mode 100644
index 0000000000000000000000000000000000000000..34162290c3616fca12487206bfb7f569aa6173a6
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/SmallCapsService/SmallCaps.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class SmallCaps extends Tools {
+  title = "Toggle Small Caps";
+  content = icons.small_caps;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.smallcaps)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.smallcaps)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/SmallCapsService/SmallCapsService.js b/wax-prosemirror-services/src/InlineAnnotations/SmallCapsService/SmallCapsService.js
new file mode 100644
index 0000000000000000000000000000000000000000..6fcb6918e02b9079eafc980d62c7efa4536877f7
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/SmallCapsService/SmallCapsService.js
@@ -0,0 +1,18 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { smallcapsMark } from "wax-prosemirror-schema";
+import SmallCaps from "./SmallCaps";
+
+class SmallCapsService extends Service {
+  register() {
+    this.container.bind("SmallCaps").to(SmallCaps);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        smallcaps: smallcapsMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default SmallCapsService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/StrikeThroughService/StrikeThrough.js b/wax-prosemirror-services/src/InlineAnnotations/StrikeThroughService/StrikeThrough.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef38b0a08335971695994a353245547f8a198b29
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/StrikeThroughService/StrikeThrough.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class StrikeThrough extends Tools {
+  title = "Toggle strikethrough";
+  content = icons.strikethrough;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.strikethrough)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.strikethrough)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/StrikeThroughService/StrikeThroughService.js b/wax-prosemirror-services/src/InlineAnnotations/StrikeThroughService/StrikeThroughService.js
new file mode 100644
index 0000000000000000000000000000000000000000..99cbfbe7f4cc81f2fce228734baba3b9995e5801
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/StrikeThroughService/StrikeThroughService.js
@@ -0,0 +1,17 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { strikethroughMark } from "wax-prosemirror-schema";
+import StrikeThrough from "./StrikeThrough";
+class StrikeThroughService extends Service {
+  register() {
+    this.container.bind("StrikeThrough").to(StrikeThrough);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        strikethrough: strikethroughMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default StrikeThroughService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/StrongService/Strong.js b/wax-prosemirror-services/src/InlineAnnotations/StrongService/Strong.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2f94db1e94422520cecb062e55457988ea12d6b
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/StrongService/Strong.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Strong extends Tools {
+  title = "Toggle strong";
+  content = icons.strong;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.strong)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.strong)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/StrongService/StrongService.js b/wax-prosemirror-services/src/InlineAnnotations/StrongService/StrongService.js
new file mode 100644
index 0000000000000000000000000000000000000000..b77b74c38281d37ddbd6bf4ac050f0c5554871b9
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/StrongService/StrongService.js
@@ -0,0 +1,24 @@
+import { toggleMark } from "prosemirror-commands";
+import Service from "wax-prosemirror-core/src/services/Service";
+import { strongMark } from "wax-prosemirror-schema";
+import Strong from "./Strong";
+
+class StrongService extends Service {
+  boot() {
+    const shortCuts = this.container.get("ShortCuts");
+    shortCuts.addShortCut({ "Mod-b": toggleMark(this.schema.marks.strong) });
+  }
+
+  register() {
+    this.container.bind("Strong").to(Strong);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        strong: strongMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default StrongService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/SubscriptService/Subscript.js b/wax-prosemirror-services/src/InlineAnnotations/SubscriptService/Subscript.js
new file mode 100644
index 0000000000000000000000000000000000000000..53ef5fc7487d8a03d445475108a7b716bc002e3b
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/SubscriptService/Subscript.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Subscript extends Tools {
+  title = "Toggle subscript";
+  content = icons.subscript;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.subscript)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.subscript)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/SubscriptService/SubscriptService.js b/wax-prosemirror-services/src/InlineAnnotations/SubscriptService/SubscriptService.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7cabf7f80159d3be6534a85f4bce0a91fefa0fa
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/SubscriptService/SubscriptService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { subscriptMark } from "wax-prosemirror-schema";
+import Subscript from "./Subscript";
+
+class SubscriptService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Subscript").to(Subscript);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        subscript: subscriptMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default SubscriptService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/SuperscriptService/Superscript.js b/wax-prosemirror-services/src/InlineAnnotations/SuperscriptService/Superscript.js
new file mode 100644
index 0000000000000000000000000000000000000000..9063597cd6496888b46fa2dd93f996f230ed55dc
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/SuperscriptService/Superscript.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Superscript extends Tools {
+  title = "Toggle superscript";
+  content = icons.superscript;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.superscript)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.superscript)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/SuperscriptService/SuperscriptService.js b/wax-prosemirror-services/src/InlineAnnotations/SuperscriptService/SuperscriptService.js
new file mode 100644
index 0000000000000000000000000000000000000000..6abb4c0d1003383babeffe84ebd52bbed78f6659
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/SuperscriptService/SuperscriptService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { superscriptMark } from "wax-prosemirror-schema";
+import Superscript from "./Superscript";
+
+class SuperscriptService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Superscript").to(Superscript);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        superscript: superscriptMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default SuperscriptService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/UnderlineService/Underline.js b/wax-prosemirror-services/src/InlineAnnotations/UnderlineService/Underline.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c1026b9c8261a558a0ca4d5a635d6f9e5d7f115
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/UnderlineService/Underline.js
@@ -0,0 +1,23 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Underline extends Tools {
+  title = "Toggle underline";
+  content = icons.underline;
+
+  get run() {
+    return (state, dispatch) => {
+      toggleMark(state.config.schema.marks.underline)(state, dispatch);
+    };
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.underline)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/InlineAnnotations/UnderlineService/UnderlineService.js b/wax-prosemirror-services/src/InlineAnnotations/UnderlineService/UnderlineService.js
new file mode 100644
index 0000000000000000000000000000000000000000..959f7406f72dd57b05227bc6ff2cdfb2bad7026f
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/UnderlineService/UnderlineService.js
@@ -0,0 +1,24 @@
+import { toggleMark } from "prosemirror-commands";
+import Service from "wax-prosemirror-core/src/services/Service";
+import { underlineMark } from "wax-prosemirror-schema";
+import Underline from "./Underline";
+
+class UnderlineService extends Service {
+  boot() {
+    const shortCuts = this.container.get("ShortCuts");
+    shortCuts.addShortCut({ "Mod-u": toggleMark(this.schema.marks.underline) });
+  }
+
+  register() {
+    this.container.bind("Underline").to(Underline);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        underline: underlineMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default UnderlineService;
diff --git a/wax-prosemirror-services/src/InlineAnnotations/index.js b/wax-prosemirror-services/src/InlineAnnotations/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..59e5880c48848bd81cee5fe3f21b7e7d738ce41e
--- /dev/null
+++ b/wax-prosemirror-services/src/InlineAnnotations/index.js
@@ -0,0 +1,19 @@
+import CodeService from "./CodeService/CodeService";
+import StrongService from "./StrongService/StrongService";
+import EmphasisService from "./EmphasisService/EmphasisService";
+import SubscriptService from "./SubscriptService/SubscriptService";
+import SuperscriptService from "./SuperscriptService/SuperscriptService";
+import StrikeThroughService from "./StrikeThroughService/StrikeThroughService";
+import UnderlineService from "./UnderlineService/UnderlineService";
+import SmallCapsService from "./SmallCapsService/SmallCapsService";
+
+export default [
+  new CodeService(),
+  new StrongService(),
+  new EmphasisService(),
+  new SubscriptService(),
+  new SuperscriptService(),
+  new StrikeThroughService(),
+  new UnderlineService(),
+  new SmallCapsService()
+];
diff --git a/wax-prosemirror-services/src/LinkService/LinkComponent.js b/wax-prosemirror-services/src/LinkService/LinkComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..5eaf74ffb447eee566827a6bba89d12bb0d331bb
--- /dev/null
+++ b/wax-prosemirror-services/src/LinkService/LinkComponent.js
@@ -0,0 +1,32 @@
+import React, { useRef, useEffect } from "react";
+import styled from "styled-components";
+// import { Button } from "wax-prosemirror-components";
+
+const LinkWrapper = styled.div`
+  padding: 20px;
+  border-radius: 3px;
+  border: 1px solid #000;
+`;
+
+const Button = styled.button``;
+
+const LinkComponent = ({ mark, setPosition, position }) => {
+  const ref = useRef(null);
+
+  useEffect(() => {
+    const width = ref.current ? ref.current.offsetWidth : 0;
+    const left = Math.abs(position.left - width / 2);
+
+    setPosition({ ...position, left });
+  }, [ref.current]);
+
+  return mark ? (
+    <LinkWrapper ref={ref}>
+      <input type="text" onChange={() => {}} value={mark.attrs.href} />
+      <Button primary>Change</Button>
+      <Button>Cancel</Button>
+    </LinkWrapper>
+  ) : null;
+};
+
+export default LinkComponent;
diff --git a/wax-prosemirror-services/src/LinkService/LinkService.js b/wax-prosemirror-services/src/LinkService/LinkService.js
new file mode 100644
index 0000000000000000000000000000000000000000..5dd1e6e40164b53562736dfbeabb1625f1605f76
--- /dev/null
+++ b/wax-prosemirror-services/src/LinkService/LinkService.js
@@ -0,0 +1,30 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+
+import LinkComponent from "./LinkComponent";
+import { linkMark } from "wax-prosemirror-schema";
+import LinkTool from "./LinkTool";
+import { OverlayService } from "../..";
+
+const PLUGIN_KEY = "LinkPlugin";
+
+export default class LinkService extends Service {
+  name = "LinkPlugin";
+
+  boot() {
+    const createOverlay = this.container.get("CreateOverlay");
+    createOverlay(LinkComponent, { markType: "link", followCursor: false });
+  }
+
+  register() {
+    this.container.bind("Link").to(LinkTool);
+    const createMark = this.container.get("CreateMark");
+    createMark(
+      {
+        link: linkMark
+      },
+      { toWaxSchema: true }
+    );
+  }
+
+  dependencies = [new OverlayService()];
+}
diff --git a/wax-prosemirror-services/src/LinkService/LinkTool.js b/wax-prosemirror-services/src/LinkService/LinkTool.js
new file mode 100644
index 0000000000000000000000000000000000000000..93696847b1458640337c7045568d96e903b672c8
--- /dev/null
+++ b/wax-prosemirror-services/src/LinkService/LinkTool.js
@@ -0,0 +1,35 @@
+import { toggleMark } from "prosemirror-commands";
+import { markActive, promptForURL } from "../lib/Utils";
+import Tools from "../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class LinkTool extends Tools {
+  title = "Add or remove link";
+  content = icons.link;
+
+  get run() {
+    return (state, dispatch) => {
+      if (markActive(state.config.schema.marks.link)(state)) {
+        toggleMark(state.config.schema.marks.link)(state, dispatch);
+        return true;
+      }
+
+      toggleMark(state.config.schema.marks.link, { href: "ld#" })(
+        state,
+        dispatch
+      );
+    };
+  }
+
+  get enable() {
+    return state => !state.selection.empty;
+  }
+
+  get active() {
+    return state => {
+      return markActive(state.config.schema.marks.link)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/ListsService/BulletListService/BulletList.js b/wax-prosemirror-services/src/ListsService/BulletListService/BulletList.js
new file mode 100644
index 0000000000000000000000000000000000000000..9caea1dc74e9fde36756688d20af42f4075d6eab
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/BulletListService/BulletList.js
@@ -0,0 +1,29 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+import { wrapInList } from "prosemirror-schema-list";
+import { blockActive } from "../../lib/Utils";
+
+@injectable()
+export default class BulletList extends Tools {
+  title = "Wrap in bullet list";
+  content = icons.bullet_list;
+
+  get run() {
+    return (state, dispatch) => {
+      return wrapInList(state.config.schema.nodes.bulletlist)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return wrapInList(state.config.schema.nodes.bulletlist)(state);
+    };
+  }
+
+  get active() {
+    return state => {
+      return blockActive(state.config.schema.nodes.bulletlist)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/ListsService/BulletListService/BulletListService.js b/wax-prosemirror-services/src/ListsService/BulletListService/BulletListService.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e2b4403a6c67e30947961344a8bbb10811a53aa
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/BulletListService/BulletListService.js
@@ -0,0 +1,20 @@
+import { bulletListNode } from "wax-prosemirror-schema";
+import Service from "wax-prosemirror-core/src/services/Service";
+import BulletList from "./BulletList";
+
+class BulletListService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("BulletList").to(BulletList);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        bulletlist: bulletListNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default BulletListService;
diff --git a/wax-prosemirror-services/src/ListsService/JoinUpService/JoinUp.js b/wax-prosemirror-services/src/ListsService/JoinUpService/JoinUp.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e5907bd1df9856bfab4e5e0c48945455deeddcc
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/JoinUpService/JoinUp.js
@@ -0,0 +1,22 @@
+import { joinUp } from "prosemirror-commands";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class JoinUp extends Tools {
+  title = "Join with above block";
+  content = icons.join_up;
+
+  get run() {
+    return joinUp;
+  }
+
+  get enable() {
+    return joinUp;
+  }
+
+  select(state) {
+    return joinUp(state);
+  }
+}
diff --git a/wax-prosemirror-services/src/ListsService/JoinUpService/JoinUpService.js b/wax-prosemirror-services/src/ListsService/JoinUpService/JoinUpService.js
new file mode 100644
index 0000000000000000000000000000000000000000..04912d389038edfb176ef6a529567b299764f53c
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/JoinUpService/JoinUpService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import JoinUp from "./JoinUp";
+
+class JoinUpService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("JoinUp").to(JoinUp);
+  }
+}
+
+export default JoinUpService;
diff --git a/wax-prosemirror-services/src/ListsService/LiftService/Lift.js b/wax-prosemirror-services/src/ListsService/LiftService/Lift.js
new file mode 100644
index 0000000000000000000000000000000000000000..2bf47008298dbb902e098d2741378d8d1a048a38
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/LiftService/Lift.js
@@ -0,0 +1,18 @@
+import { lift } from "prosemirror-commands";
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Lift extends Tools {
+  title = "Lift out of enclosing block";
+  content = icons.lift;
+
+  get run() {
+    return lift;
+  }
+
+  get enable() {
+    return lift;
+  }
+}
diff --git a/wax-prosemirror-services/src/ListsService/LiftService/LiftService.js b/wax-prosemirror-services/src/ListsService/LiftService/LiftService.js
new file mode 100644
index 0000000000000000000000000000000000000000..19e42ad303ba7ea8215d1b9afbdc9f3e31ae8b77
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/LiftService/LiftService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Lift from "./Lift";
+
+class LiftService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Lift").to(Lift);
+  }
+}
+
+export default LiftService;
diff --git a/wax-prosemirror-services/src/ListsService/ListItemService/ListItemService.js b/wax-prosemirror-services/src/ListsService/ListItemService/ListItemService.js
new file mode 100644
index 0000000000000000000000000000000000000000..1de99c1bcfb9cac28f0d8d44f4042e63958f162d
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/ListItemService/ListItemService.js
@@ -0,0 +1,18 @@
+import { listItemNode } from "wax-prosemirror-schema";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class ListItemService extends Service {
+  boot() {}
+
+  register() {
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        list_item: listItemNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default ListItemService;
diff --git a/wax-prosemirror-services/src/ListsService/ListsService.js b/wax-prosemirror-services/src/ListsService/ListsService.js
new file mode 100644
index 0000000000000000000000000000000000000000..b9fff5437466c0377ef98d0c8865b68884b3efe8
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/ListsService.js
@@ -0,0 +1,8 @@
+import ListsServices from "./index";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class ListsService extends Service {
+  dependencies = ListsServices;
+}
+
+export default ListsService;
diff --git a/wax-prosemirror-services/src/ListsService/OrderedListService/OrderedList.js b/wax-prosemirror-services/src/ListsService/OrderedListService/OrderedList.js
new file mode 100644
index 0000000000000000000000000000000000000000..cff84727cdd3c4421c297c77091a8348dd53e51b
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/OrderedListService/OrderedList.js
@@ -0,0 +1,29 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+import { wrapInList } from "prosemirror-schema-list";
+import { blockActive } from "../../lib/Utils";
+
+@injectable()
+export default class OrderedList extends Tools {
+  title = "Wrap in ordered list";
+  content = icons.ordered_list;
+
+  get run() {
+    return (state, dispatch) => {
+      wrapInList(state.config.schema.nodes.orderedlist)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return wrapInList(state.config.schema.nodes.orderedlist)(state);
+    };
+  }
+
+  get active() {
+    return state => {
+      return blockActive(state.config.schema.nodes.orderedlist)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/ListsService/OrderedListService/OrderedListService.js b/wax-prosemirror-services/src/ListsService/OrderedListService/OrderedListService.js
new file mode 100644
index 0000000000000000000000000000000000000000..42ca2d420f68829ab1c3467fe64c0f9edbe4b3fd
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/OrderedListService/OrderedListService.js
@@ -0,0 +1,20 @@
+import { orderedListNode } from "wax-prosemirror-schema";
+import Service from "wax-prosemirror-core/src/services/Service";
+import OrderedList from "./OrderedList";
+
+class OrderedListService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("OrderedList").to(OrderedList);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        orderedlist: orderedListNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default OrderedListService;
diff --git a/wax-prosemirror-services/src/ListsService/index.js b/wax-prosemirror-services/src/ListsService/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..628800e85c94764016a8c4bfb82c09d7b1177f0a
--- /dev/null
+++ b/wax-prosemirror-services/src/ListsService/index.js
@@ -0,0 +1,13 @@
+import BulletListService from "./BulletListService/BulletListService";
+import OrderedListService from "./OrderedListService/OrderedListService";
+import JoinUpService from "./JoinUpService/JoinUpService";
+import LiftService from "./LiftService/LiftService";
+import ListItemService from "./ListItemService/ListItemService";
+
+export default [
+  new BulletListService(),
+  new OrderedListService(),
+  new JoinUpService(),
+  new LiftService(),
+  new ListItemService()
+];
diff --git a/wax-prosemirror-services/src/MenuService/Menu.js b/wax-prosemirror-services/src/MenuService/Menu.js
new file mode 100644
index 0000000000000000000000000000000000000000..f08b30ea9e19f5d8ae355fd8b33a1238afad6678
--- /dev/null
+++ b/wax-prosemirror-services/src/MenuService/Menu.js
@@ -0,0 +1,39 @@
+import React, { useMemo, useContext } from "react";
+import { injectable } from "inversify";
+import ToolGroup from "../lib/ToolGroup";
+
+import MenuWrapper from "./MenuWrapper";
+import { WaxContext } from "wax-prosemirror-core/src/ioc-react";
+
+@injectable()
+export default class Menu {
+  toolGroups = [];
+  config = {};
+  name = "";
+  constructor(config, createTools) {
+    this.name = config.name;
+    this.config = config;
+    this.toolGroups = createTools(this.config.toolGroups);
+    this.excludeIncludeTools();
+  }
+
+  excludeIncludeTools() {
+    this.toolGroups.forEach(toolGroup => {
+      if (toolGroup instanceof ToolGroup) {
+        toolGroup.excludeIncludeTools();
+      }
+    });
+  }
+
+  render() {
+    return () => {
+      const {
+        view: { main }
+      } = useContext(WaxContext);
+      const Bar = useMemo(() => (
+        <MenuWrapper items={this.toolGroups} view={main || {}} />
+      ));
+      return <>{Bar}</>;
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/MenuService/MenuCollection.js b/wax-prosemirror-services/src/MenuService/MenuCollection.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab72fc3b52f6266a750251c44aab2ea2194db68c
--- /dev/null
+++ b/wax-prosemirror-services/src/MenuService/MenuCollection.js
@@ -0,0 +1,13 @@
+import { injectable, multiInject } from "inversify";
+
+@injectable()
+export default class MenuCollection {
+  menus = [];
+  constructor(@multiInject("Menu") menus) {
+    this.menus = menus;
+  }
+
+  getMenu(name) {
+    return this.menus.find(menu => menu.name === name);
+  }
+}
diff --git a/wax-prosemirror-services/src/MenuService/MenuService.js b/wax-prosemirror-services/src/MenuService/MenuService.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a8f2a92b206d5f68b21c94b6a4bb0a2b58a28cd
--- /dev/null
+++ b/wax-prosemirror-services/src/MenuService/MenuService.js
@@ -0,0 +1,56 @@
+import { isPlainObject, isFunction } from "lodash";
+import Menu from "./Menu";
+import MenuCollection from "./MenuCollection";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+export default class MenuService extends Service {
+  name = "MenuService";
+  boot() {
+    const { menus } = this.container.get("MenuCollection");
+    const layout = this.container.get("Layout");
+    menus.forEach(menu => {
+      layout.addComponent(menu.config.templateArea, menu.render());
+    });
+  }
+
+  register() {
+    /* create Menu Factory */
+    this.config.map(conf => {
+      this.container.bind("Menu").toFactory(context => {
+        return new Menu(conf, context.container.get("createTools"));
+      });
+    });
+
+    /*create MenuCollection of Menus */
+    this.container
+      .bind("MenuCollection")
+      .to(MenuCollection)
+      .inSingletonScope();
+
+    /* create factory of tools */
+    this.container.bind("createTools").toFactory(context => {
+      return configTools => {
+        const tools = [];
+        configTools.forEach(tool => {
+          try {
+            let tl = {};
+            if (isPlainObject(tool)) {
+              tl = context.container.get(tool.name);
+              tl.setGroupConfig(tool);
+            } else if (isFunction(tool)) {
+              tl = context.container.get(tool());
+            } else {
+              tl = context.container.get(tool);
+            }
+            tools.push(tl);
+          } catch (error) {
+            throw Error(
+              `Could not load Service ${tool.name}. Please configure service through config`
+            );
+          }
+        });
+        return tools;
+      };
+    });
+  }
+}
diff --git a/wax-prosemirror-services/src/MenuService/MenuWrapper.js b/wax-prosemirror-services/src/MenuService/MenuWrapper.js
new file mode 100644
index 0000000000000000000000000000000000000000..471d9d621066a18e236d4589b7d001cd74eaa7ad
--- /dev/null
+++ b/wax-prosemirror-services/src/MenuService/MenuWrapper.js
@@ -0,0 +1,21 @@
+import React from "react";
+import styled from "styled-components";
+
+import { map } from "lodash";
+
+const MainMenu = styled.div`
+  background: #fff;
+  padding: 2px 2px 2px 0;
+  position: relative;
+  background: transparent;
+`;
+
+const MainMenuBar = ({ items = [], view }) => {
+  return (
+    <MainMenu key="MainMenu">
+      {map(items, item => item.renderTools(view))}
+    </MainMenu>
+  );
+};
+
+export default MainMenuBar;
diff --git a/wax-prosemirror-services/src/ModalService/ModalComponent.js b/wax-prosemirror-services/src/ModalService/ModalComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..1524d87e8ed9300e5596bf96f0e345d9dc1896c2
--- /dev/null
+++ b/wax-prosemirror-services/src/ModalService/ModalComponent.js
@@ -0,0 +1,9 @@
+import React, { useMemo } from "react";
+
+export default (Component, plugin) => ({ view }) => (
+  <div>
+    <Component {...plugin.getState(view.state)} />
+    Overlay Area
+  </div>
+);
+//
diff --git a/wax-prosemirror-services/src/ModalService/ModalService.js b/wax-prosemirror-services/src/ModalService/ModalService.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0251439311809f117e70e25de6ecf9448e0a4d5
--- /dev/null
+++ b/wax-prosemirror-services/src/ModalService/ModalService.js
@@ -0,0 +1,23 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import ModalPlugin from "./pmPlugins/ModalPlugin";
+import ModalComponent from "./ModalComponent";
+const PLUGIN_KEY = "overlay";
+
+export default class ModalService extends Service {
+  boot() {
+    this.app.PmPlugins.add(PLUGIN_KEY, ModalPlugin(PLUGIN_KEY));
+  }
+  register() {
+    this.container.bind("CreateModal").toFactory(context => {
+      return (Component, pluginName) => {
+        const PmPlugins = context.container.get("PmPlugins");
+        const plugin = PmPlugins.get(pluginName);
+        const layout = context.container.get("Layout");
+        layout.addComponent(
+          "editorOverlays",
+          ModalComponent(Component, plugin)
+        );
+      };
+    });
+  }
+}
diff --git a/wax-prosemirror-services/src/ModalService/pmPlugins/ModalPlugin.js b/wax-prosemirror-services/src/ModalService/pmPlugins/ModalPlugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d744579a02b21189a7c5df0e356181b7076bb3d
--- /dev/null
+++ b/wax-prosemirror-services/src/ModalService/pmPlugins/ModalPlugin.js
@@ -0,0 +1,14 @@
+import { Plugin, PluginKey } from "prosemirror-state";
+import actions from "./actions";
+export default key =>
+  new Plugin({
+    key: new PluginKey(key),
+    state: {
+      init: function init() {
+        return {
+          action: actions.HIDE_OVERLAY
+        };
+      },
+      apply: function apply(tr) {}
+    }
+  });
diff --git a/wax-prosemirror-services/src/ModalService/pmPlugins/actions.js b/wax-prosemirror-services/src/ModalService/pmPlugins/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..37467a091ba7f7bc69065e235aed2517709a63c3
--- /dev/null
+++ b/wax-prosemirror-services/src/ModalService/pmPlugins/actions.js
@@ -0,0 +1,4 @@
+export default {
+  HIDE_OVERLAY: "HIDE_OVERLAY",
+  SHOW_OVERLAY: "SHOW_OVERLAY"
+};
diff --git a/wax-prosemirror-services/src/NoteService/Editor.js b/wax-prosemirror-services/src/NoteService/Editor.js
new file mode 100644
index 0000000000000000000000000000000000000000..dcbe3e222875d72af698df598df1c11f1c640a84
--- /dev/null
+++ b/wax-prosemirror-services/src/NoteService/Editor.js
@@ -0,0 +1,95 @@
+import React, { useEffect, useRef, useContext } from "react";
+import { EditorView } from "prosemirror-view";
+import { EditorState } from "prosemirror-state";
+import { StepMap } from "prosemirror-transform";
+import { keymap } from "prosemirror-keymap";
+import { undo, redo } from "prosemirror-history";
+import { WaxContext } from "wax-prosemirror-core/src/ioc-react";
+
+import { markActive } from "../lib/Utils";
+
+export default ({ node, view, pos }) => {
+  const editorRef = useRef();
+  const context = useContext(WaxContext);
+
+  useEffect(() => {
+    const noteView = new EditorView(
+      { mount: editorRef.current },
+      {
+        state: EditorState.create({
+          doc: node,
+          plugins: [
+            keymap({
+              "Mod-z": () => undo(view.state, view.dispatch),
+              "Mod-y": () => redo(view.state, view.dispatch),
+              "Mod-u": () =>
+                markActive(noteView.state.config.schema.marks.underline)(
+                  noteView.state
+                )
+            })
+          ]
+        }),
+        // This is the magic part
+        dispatchTransaction: tr => {
+          let { state, transactions } = noteView.state.applyTransaction(tr);
+          noteView.updateState(state);
+
+          if (!tr.getMeta("fromOutside")) {
+            let outerTr = view.state.tr,
+              offsetMap = StepMap.offset(pos + 1);
+            console.log(transactions, 1111111);
+            for (let i = 0; i < transactions.length; i++) {
+              let steps = transactions[i].steps;
+              for (let j = 0; j < steps.length; j++)
+                outerTr.step(steps[j].map(offsetMap));
+            }
+
+            // outerTr.setNodeMarkup(pos, view.state.schema.nodes.footnote, {
+            //   title: noteView.docView.node.textContent
+            // });
+
+            if (outerTr.docChanged) {
+              view.dispatch(outerTr);
+            }
+          }
+        },
+        handleDOMEvents: {
+          mousedown: () => {
+            // Kludge to prevent issues due to the fact that the whole
+            // footnote is node-selected (and thus DOM-selected) when
+            // the parent editor is focused.
+            if (noteView.hasFocus()) noteView.focus();
+          }
+        }
+      }
+    );
+    context.updateView({ [pos]: noteView });
+  }, []);
+
+  if (context.view[pos]) {
+    console.log(1);
+    let state = context.view[pos].state;
+    let start = node.content.findDiffStart(state.doc.content);
+    console.log(start, node);
+    if (start != null) {
+      let { a: endA, b: endB } = node.content.findDiffEnd(state.doc.content);
+      let overlap = start - Math.min(endA, endB);
+      if (overlap > 0) {
+        endA += overlap;
+        endB += overlap;
+      }
+      context.view[pos].dispatch(
+        state.tr
+          .replace(start, endB, node.slice(start, endA))
+          .setMeta("fromOutside", true)
+      );
+    }
+  }
+
+  return (
+    <div
+      style={{ height: "100px", border: "1px solid black" }}
+      ref={editorRef}
+    ></div>
+  );
+};
diff --git a/wax-prosemirror-services/src/NoteService/Note.js b/wax-prosemirror-services/src/NoteService/Note.js
new file mode 100644
index 0000000000000000000000000000000000000000..c270e7a5bc79e46eb5361787f24b585dd4bd5137
--- /dev/null
+++ b/wax-prosemirror-services/src/NoteService/Note.js
@@ -0,0 +1,18 @@
+import Tools from "../lib/Tools";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Note extends Tools {
+  title = "Insert Note";
+  content = icons.footnote;
+
+  get run() {
+    return (state, dispatch) => {
+      const footnote = state.config.schema.nodes.footnote.create();
+      dispatch(state.tr.replaceSelectionWith(footnote));
+    };
+  }
+
+  get enable() {}
+}
diff --git a/wax-prosemirror-services/src/NoteService/NoteComponent.js b/wax-prosemirror-services/src/NoteService/NoteComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..6a13e25d8787f4b7c333f9536e160f529f3e6efc
--- /dev/null
+++ b/wax-prosemirror-services/src/NoteService/NoteComponent.js
@@ -0,0 +1,65 @@
+import React, { useContext, useState, useEffect, useMemo } from "react";
+import { WaxContext } from "wax-prosemirror-core/src/ioc-react";
+import { isEqual } from "lodash";
+import NoteEditor from "./NoteEditor";
+
+export default () => {
+  const {
+    view: { main }
+  } = useContext(WaxContext);
+  const [notes, setNotes] = useState([]);
+
+  useEffect(() => {
+    setNotes(updateNotes(main));
+  }, [JSON.stringify(updateNotes(main))]);
+
+  const noteComponent = useMemo(
+    () => <NoteEditor notes={notes} view={main} />,
+    [notes]
+  );
+
+  return <div>{noteComponent}</div>;
+};
+
+const updateNotes = view => {
+  if (view) {
+    return findBlockNodes(
+      view.state.doc,
+      view.state.schema.nodes.footnote,
+      true
+    );
+  }
+  return [];
+};
+
+export const flatten = (node, descend = true) => {
+  if (!node) {
+    throw new Error('Invalid "node" parameter');
+  }
+  const result = [];
+  node.descendants((child, pos) => {
+    result.push({ node: child, pos });
+    if (!descend) {
+      return false;
+    }
+  });
+  return result;
+};
+
+export const findChildren = (node, predicate, descend) => {
+  if (!node) {
+    throw new Error('Invalid "node" parameter');
+  } else if (!predicate) {
+    throw new Error('Invalid "predicate" parameter');
+  }
+  return flatten(node, descend).filter(child => {
+    // predicate(child.node)console.log(child.node);
+    // return predicate(child.node);
+    // console.log(child.node.type.name === "footnote", predicate(child.node));
+    return child.node.type.name === "footnote" ? child.node : false;
+  });
+};
+
+export const findBlockNodes = (node, descend) => {
+  return findChildren(node, child => child.isBlock, descend);
+};
diff --git a/wax-prosemirror-services/src/NoteService/NoteEditor.js b/wax-prosemirror-services/src/NoteService/NoteEditor.js
new file mode 100644
index 0000000000000000000000000000000000000000..23c61ea7767d15e8886be40bc3a0e8574b904e55
--- /dev/null
+++ b/wax-prosemirror-services/src/NoteService/NoteEditor.js
@@ -0,0 +1,22 @@
+import React, { useMemo } from "react";
+import Editor from "./Editor";
+
+export default ({ notes, view }) => {
+  // const EditorComponent = useMemo(
+  //   () => <Editor node={note.node} pos={note.pos} view={view} />,
+  //   [notes]
+  // );
+
+  return (
+    <div>
+      {notes.map(note => (
+        <Editor
+          key={`editor-${note.pos}`}
+          node={note.node}
+          pos={note.pos}
+          view={view}
+        />
+      ))}
+    </div>
+  );
+};
diff --git a/wax-prosemirror-services/src/NoteService/NoteService.js b/wax-prosemirror-services/src/NoteService/NoteService.js
new file mode 100644
index 0000000000000000000000000000000000000000..57ef932615d4f15a42192950aad26b8ad71a0ead
--- /dev/null
+++ b/wax-prosemirror-services/src/NoteService/NoteService.js
@@ -0,0 +1,18 @@
+import Note from "./Note";
+import Service from "wax-prosemirror-core/src/services/Service";
+import NoteComponent from "./NoteComponent";
+
+class NoteService extends Service {
+  name = "NoteService";
+
+  boot() {
+    const layout = this.container.get("Layout");
+    layout.addComponent("bottomBar", NoteComponent);
+  }
+
+  register() {
+    this.container.bind("Note").to(Note);
+  }
+}
+
+export default NoteService;
diff --git a/wax-prosemirror-services/src/OverlayService/OverlayComponent.js b/wax-prosemirror-services/src/OverlayService/OverlayComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe93ec681bcd026c2a1b3dec9d120267b72e028d
--- /dev/null
+++ b/wax-prosemirror-services/src/OverlayService/OverlayComponent.js
@@ -0,0 +1,16 @@
+import React, { useMemo } from "react";
+import usePosition from "./usePosition";
+import { Overlay } from "wax-prosemirror-components";
+
+export default (Component, markType) => () => {
+  const [position, setPosition, mark] = usePosition(markType);
+  const component = useMemo(
+    () => (
+      <Component setPosition={setPosition} mark={mark} position={position} />
+    ),
+    [JSON.stringify(mark), position]
+  );
+  const visible = position.left ? true : false;
+
+  return <Overlay position={position}>{visible && component}</Overlay>;
+};
diff --git a/wax-prosemirror-services/src/OverlayService/OverlayService.js b/wax-prosemirror-services/src/OverlayService/OverlayService.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c156844ecbd8d8a547d84be6801c961a39d00ac
--- /dev/null
+++ b/wax-prosemirror-services/src/OverlayService/OverlayService.js
@@ -0,0 +1,19 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+
+import OverlayComponent from "./OverlayComponent";
+
+export default class OverlayService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("CreateOverlay").toFactory(context => {
+      return (Component, options) => {
+        const layout = context.container.get("Layout");
+        layout.addComponent(
+          "waxOverlays",
+          OverlayComponent(Component, options)
+        );
+      };
+    });
+  }
+}
diff --git a/wax-prosemirror-services/src/OverlayService/usePosition.js b/wax-prosemirror-services/src/OverlayService/usePosition.js
new file mode 100644
index 0000000000000000000000000000000000000000..308ac1dda790f58b5896f80237d3eef443a11aee
--- /dev/null
+++ b/wax-prosemirror-services/src/OverlayService/usePosition.js
@@ -0,0 +1,63 @@
+import { useState, useContext, useEffect, useCallback } from "react";
+import { isObject } from "lodash";
+import { markActive, getMarkPosition } from "../lib/Utils";
+import { WaxContext } from "wax-prosemirror-core/src/ioc-react";
+
+const defaultOverlay = {
+  left: null,
+  top: null,
+  from: null,
+  to: null,
+  mark: null
+};
+
+export default options => {
+  const {
+    view: { main }
+  } = useContext(WaxContext);
+
+  const [position, setPosition] = useState({
+    position: "absolute",
+    ...defaultOverlay
+  });
+
+  let mark = {};
+
+  const updatePosition = useCallback((followCursor = true) => {
+    if (!main) return defaultOverlay;
+
+    mark = markActive(main.state.schema.marks[options.markType])(main.state);
+
+    if (!isObject(mark)) return defaultOverlay;
+
+    const { from, to } = isObject(mark)
+      ? followCursor
+        ? main.state.selection
+        : getMarkPosition(main.state.selection.$anchor, mark)
+      : main.state.selection;
+
+    const start = main.coordsAtPos(from);
+
+    const box = main.dom.offsetParent.getBoundingClientRect();
+
+    let left = start.left - box.left;
+    let top = start.top - box.top + 20;
+
+    return {
+      left,
+      top,
+      from,
+      to,
+      mark
+    };
+  });
+
+  useEffect(() => {
+    setPosition({
+      position: "absolute",
+      ...updatePosition(options.followCursor)
+    });
+  }, [JSON.stringify(updatePosition(options.followCursor))]);
+
+  return [position, setPosition, mark];
+};
diff --git a/wax-prosemirror-services/src/PlaceholderService/PlaceholderService.js b/wax-prosemirror-services/src/PlaceholderService/PlaceholderService.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad017bcec66e7274a2c951aaa302ebfbc9edc3c7
--- /dev/null
+++ b/wax-prosemirror-services/src/PlaceholderService/PlaceholderService.js
@@ -0,0 +1,11 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import placeholderPlugin from "./pmPlugins/placeholderPlugin";
+const PLUGIN_KEY = "imagePlaceHolder";
+
+export default class PlaceholderService extends Service {
+  name = "PlaceholderService";
+
+  boot() {
+    this.app.PmPlugins.add(PLUGIN_KEY, placeholderPlugin(PLUGIN_KEY));
+  }
+}
diff --git a/wax-prosemirror-services/src/PlaceholderService/pmPlugins/placeholderPlugin.js b/wax-prosemirror-services/src/PlaceholderService/pmPlugins/placeholderPlugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..805e5027592a417421549e7a78e7388e26e97a4f
--- /dev/null
+++ b/wax-prosemirror-services/src/PlaceholderService/pmPlugins/placeholderPlugin.js
@@ -0,0 +1,36 @@
+import { Plugin, PluginKey } from "prosemirror-state";
+import { Decoration, DecorationSet } from "prosemirror-view";
+
+export default key =>
+  new Plugin({
+    key: new PluginKey(key),
+    state: {
+      init: function init() {
+        return DecorationSet.empty;
+      },
+      apply: function apply(tr, set) {
+        console.log(tr, "placeholderPLugin");
+        // Adjust decoration positions to changes made by the transaction
+        set = set.map(tr.mapping, tr.doc);
+        // See if the transaction adds or removes any placeholders
+        const action = tr.getMeta(this);
+        if (action && action.add) {
+          const widget = document.createElement("placeholder");
+          const deco = Decoration.widget(action.add.pos, widget, {
+            id: action.add.id
+          });
+          set = set.add(tr.doc, [deco]);
+        } else if (action && action.remove) {
+          set = set.remove(
+            set.find(null, null, spec => spec.id === action.remove.id)
+          );
+        }
+        return set;
+      }
+    },
+    props: {
+      decorations: function decorations(state) {
+        return this.getState(state);
+      }
+    }
+  });
diff --git a/wax-prosemirror-services/src/RulesService/Rules.js b/wax-prosemirror-services/src/RulesService/Rules.js
new file mode 100644
index 0000000000000000000000000000000000000000..43c7fa1549629615bba8dc7d70ee110a5fee723d
--- /dev/null
+++ b/wax-prosemirror-services/src/RulesService/Rules.js
@@ -0,0 +1,57 @@
+import { injectable } from "inversify";
+import {
+  inputRules,
+  wrappingInputRule,
+  textblockTypeInputRule,
+  smartQuotes
+} from "prosemirror-inputrules";
+
+@injectable()
+class Rules {
+  constructor(plugins, schema) {
+    this.PmPlugins = plugins;
+
+    this.schema = schema;
+    this.extendedRules = this.allRules();
+  }
+
+  addRule(rules) {
+    this.extendedRules.push(...rules);
+  }
+
+  createRules() {
+    const rulesCreated = inputRules({ rules: this.extendedRules });
+    this.PmPlugins.add("rules", rulesCreated);
+  }
+
+  allRules() {
+    return [
+      ...smartQuotes,
+      // > blockquote
+      wrappingInputRule(/^\s*>\s$/, this.schema.nodes.blockquote),
+
+      // 1. ordered list
+      wrappingInputRule(
+        /^(\d+)\.\s$/,
+        this.schema.nodes.ordered_list,
+        match => ({ order: +match[1] }),
+        (match, node) => node.childCount + node.attrs.order === +match[1]
+      ),
+
+      // * bullet list
+      wrappingInputRule(/^\s*([-+*])\s$/, this.schema.nodes.bullet_list),
+
+      // ``` code block
+      textblockTypeInputRule(/^```$/, this.schema.nodes.code_block),
+
+      // # heading
+      textblockTypeInputRule(
+        new RegExp("^(#{1,6})\\s$"),
+        this.schema.nodes.heading,
+        match => ({ level: match[1].length })
+      )
+    ];
+  }
+}
+
+export default Rules;
diff --git a/wax-prosemirror-services/src/RulesService/RulesService.js b/wax-prosemirror-services/src/RulesService/RulesService.js
new file mode 100644
index 0000000000000000000000000000000000000000..a298a98582c97110c9c17227269f509835d55a40
--- /dev/null
+++ b/wax-prosemirror-services/src/RulesService/RulesService.js
@@ -0,0 +1,28 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Rules from "./Rules";
+
+export default class RulesService extends Service {
+  name = "RulesService";
+
+  boot() {
+    const configRules = this.config;
+    const rules = this.container.get("Rules");
+    rules.addRule(configRules);
+    rules.createRules();
+  }
+
+  register() {
+    const PmPlugins = this.app.PmPlugins;
+
+    this.container
+      .bind("Rules")
+      .toDynamicValue(() => {
+        const {
+          schema: { schema }
+        } = this.app;
+
+        return new Rules(PmPlugins, schema);
+      })
+      .inSingletonScope();
+  }
+}
diff --git a/wax-prosemirror-services/src/SchemaService/DefaultSchema.js b/wax-prosemirror-services/src/SchemaService/DefaultSchema.js
new file mode 100644
index 0000000000000000000000000000000000000000..73541c6d32767d87ecc45286d7e547d4e8bffb51
--- /dev/null
+++ b/wax-prosemirror-services/src/SchemaService/DefaultSchema.js
@@ -0,0 +1,77 @@
+const blockLevelToDOM = node => {
+  const attrs = node.attrs.track.length
+    ? {
+        class: node.attrs.class,
+        "data-track": JSON.stringify(node.attrs.track)
+      }
+    : { class: node.attrs.class };
+  return attrs;
+};
+
+export default {
+  nodes: {
+    doc: {
+      content: "block+"
+    },
+    text: {
+      group: "inline"
+    },
+    hard_break: {
+      inline: true,
+      group: "inline",
+      selectable: false,
+      parseDOM: [{ tag: "br" }],
+      toDOM() {
+        return ["br"];
+      }
+    },
+    paragraph: {
+      group: "block",
+      content: "inline*",
+      attrs: {
+        class: { default: "paragraph" },
+        track: { default: [] }
+      },
+      parseDOM: [
+        {
+          tag: "p.paragraph",
+          getAttrs(dom) {
+            return {
+              class: dom.getAttribute("class"),
+              track: parseTracks(dom.dataset.track)
+            };
+          }
+        }
+      ],
+      toDOM(node) {
+        const attrs = blockLevelToDOM(node);
+        return ["p", attrs, 0];
+      }
+    },
+    footnote: {
+      group: "inline",
+      content: "inline*",
+      inline: true,
+      // This makes the view treat the node as a leaf, even though it
+      // technically has content
+      atom: true,
+      toDOM: () => ["footnote"],
+      parseDOM: [{ tag: "footnote" }]
+    }
+    // footnote: {
+    //   group: "inline",
+    //   content: "block+",
+    //   inline: true,
+    //   atom: true,
+    //   toDOM: dom => {
+    //     return ["footnote"];
+    //   },
+    //   parseDOM: [
+    //     {
+    //       tag: "footnote"
+    //     }
+    //   ]
+    // },
+  },
+  marks: {}
+};
diff --git a/wax-prosemirror-services/src/SchemaService/Mark.js b/wax-prosemirror-services/src/SchemaService/Mark.js
new file mode 100644
index 0000000000000000000000000000000000000000..eaa0e99e9dd79d15384c87f72aea9efa8a882e20
--- /dev/null
+++ b/wax-prosemirror-services/src/SchemaService/Mark.js
@@ -0,0 +1,75 @@
+import { isPlainObject } from "lodash";
+import ParseRule from "./ParseRule";
+import Middleware from "../lib/Middleware";
+
+export default class Mark {
+  name = "";
+  importer = {};
+
+  inline = false;
+  group = "";
+  content = "";
+  draggable = false;
+  _attrs = {};
+  _parseRules = [];
+
+  constructor(name) {
+    this.name = name;
+    this.importer = new Middleware();
+  }
+
+  fromJSON(config) {
+    for (let key in config) {
+      let value = config[key];
+      this[key] = value;
+    }
+  }
+
+  set toDOM(value) {
+    this.importer.use(value);
+  }
+
+  set attrs(value) {
+    Object.assign(this._attrs, value);
+  }
+
+  set parseDOM(parseDom) {
+    let values = parseDom;
+    if (isPlainObject(parseDom)) {
+      values = [parseDom];
+    }
+    values.forEach(value => {
+      let parseRule = this._parseRules.find(parseRule => {
+        if (value.tag) return parseRule.tag === value.tag;
+        if (value.style) return parseRule.style === value.style;
+        return false;
+      });
+      if (!parseRule) {
+        parseRule = new ParseRule(value);
+        this._parseRules.push(parseRule);
+      }
+      parseRule.addStack(value.getAttrs);
+    });
+  }
+
+  toJSON() {
+    const importer = this.importer;
+
+    return {
+      inline: this.inline,
+      group: this.group,
+      content: this.content,
+      draggable: this.draggable,
+      attrs: this._attrs,
+      parseDOM: this._parseRules.map(rule => rule.combineRules()),
+      toDOM: node => {
+        let hooks = {};
+
+        importer.go({ node }, hook => {
+          hooks = hook;
+        });
+        return hooks.value;
+      }
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/SchemaService/Node.js b/wax-prosemirror-services/src/SchemaService/Node.js
new file mode 100644
index 0000000000000000000000000000000000000000..c3108aea345571c4ec27a430dd05e603b16517ca
--- /dev/null
+++ b/wax-prosemirror-services/src/SchemaService/Node.js
@@ -0,0 +1,77 @@
+import { isPlainObject } from "lodash";
+import ParseRule from "./ParseRule";
+import Middleware from "../lib/Middleware";
+
+export default class Node {
+  name = "";
+  importer = {};
+
+  isolating = false;
+  inline = false;
+  group = "";
+  content = "";
+  draggable = false;
+  _attrs = {};
+  _parseRules = [];
+
+  constructor(name) {
+    this.name = name;
+    this.importer = new Middleware();
+  }
+
+  fromJSON(config) {
+    for (let key in config) {
+      let value = config[key];
+      this[key] = value;
+    }
+  }
+
+  set toDOM(value) {
+    this.importer.use(value);
+  }
+
+  set attrs(value) {
+    Object.assign(this._attrs, value);
+  }
+
+  set parseDOM(parseDom) {
+    let values = parseDom;
+    if (isPlainObject(parseDom)) {
+      values = [parseDom];
+    }
+    values.forEach(value => {
+      let parseRule = this._parseRules.find(parseRule => {
+        if (value.tag) return parseRule.tag === value.tag;
+        if (value.style) return parseRule.style === value.style;
+        return false;
+      });
+      if (!parseRule) {
+        parseRule = new ParseRule(value);
+        this._parseRules.push(parseRule);
+      }
+      parseRule.addStack(value.getAttrs);
+    });
+  }
+
+  toJSON() {
+    const importer = this.importer;
+
+    return {
+      inline: this.inline,
+      group: this.group,
+      content: this.content,
+      isolating: this.isolating,
+      draggable: this.draggable,
+      attrs: this._attrs,
+      parseDOM: this._parseRules.map(rule => rule.combineRules()),
+      toDOM: node => {
+        let hooks = {};
+
+        importer.go({ node }, hook => {
+          hooks = hook;
+        });
+        return hooks.value;
+      }
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/SchemaService/ParseRule.js b/wax-prosemirror-services/src/SchemaService/ParseRule.js
new file mode 100644
index 0000000000000000000000000000000000000000..03a91f519c0707016570a11613f4cc69ae8a21e8
--- /dev/null
+++ b/wax-prosemirror-services/src/SchemaService/ParseRule.js
@@ -0,0 +1,52 @@
+import { omit } from "lodash";
+import Middleware from "../lib/Middleware";
+
+export default class ParseRule {
+  tag = null;
+  style = null;
+  exporter = null;
+
+  constructor({ getAttrs, tag, style }) {
+    this.tag = tag;
+    this.style = style;
+    if (getAttrs) {
+      this.exporter = new Middleware();
+    }
+    this.addStack(getAttrs);
+  }
+
+  addStack(getAttrs) {
+    if (getAttrs) {
+      this.exporter.use(getAttrs);
+    }
+  }
+
+  parseSchema(exporter) {
+    let rule = {};
+    if (this.tag) {
+      rule = { tag: this.tag };
+    }
+
+    if (this.style) {
+      rule = { style: this.style };
+    }
+
+    if (this.exporter) {
+      rule.getAttrs = dom => {
+        let hooks = {};
+
+        exporter.go({ dom }, hook => {
+          hooks = hook;
+        });
+        return omit(hooks, ["dom"]);
+      };
+    }
+
+    return rule;
+  }
+
+  combineRules() {
+    const exporter = this.exporter;
+    return this.parseSchema(exporter);
+  }
+}
diff --git a/wax-prosemirror-services/src/SchemaService/Schema.js b/wax-prosemirror-services/src/SchemaService/Schema.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b935080d963b0baccc5dbfc9cc4af16d50f4f55
--- /dev/null
+++ b/wax-prosemirror-services/src/SchemaService/Schema.js
@@ -0,0 +1,101 @@
+import { Schema as PmPschema } from "prosemirror-model";
+import { injectable } from "inversify";
+import DefaultSchema from "./DefaultSchema";
+
+import Node from "./Node";
+import Mark from "./Mark";
+
+@injectable()
+export default class Schema {
+  _nodes = {};
+  _marks = {};
+  prosemirrorSchema = { nodes: {}, marks: {} };
+  schema = null;
+
+  addNode(schemaConfig) {
+    const name = Object.keys(schemaConfig)[0];
+    const config = schemaConfig[name];
+
+    const node = new Node(name);
+    let nd = {};
+
+    if ((nd = this.has(node))) {
+      nd.fromJSON(config);
+      return nd;
+    } else {
+      node.fromJSON(config);
+      this.addSchema(node);
+
+      return { [name]: node };
+    }
+  }
+
+  addMark(schemaConfig) {
+    const name = Object.keys(schemaConfig)[0];
+    const config = schemaConfig[name];
+
+    const mark = new Mark(name);
+    let mr = {};
+    if ((mr = this.has(mark))) {
+      mr.fromJSON(config);
+      return mr;
+    } else {
+      mark.fromJSON(config);
+      this.addSchema(mark);
+      return { [name]: mark };
+    }
+  }
+
+  has(instance) {
+    if (instance instanceof Node) {
+      return this._nodes[instance.name] ? this._nodes[instance.name] : false;
+    }
+    if (instance instanceof Mark) {
+      return this._marks[instance.name] ? this._marks[instance.name] : false;
+    }
+  }
+
+  addSchema(instance) {
+    if (instance instanceof Node) {
+      return this._nodes[instance.name]
+        ? this._nodes[instance.name]
+        : Object.assign(this._nodes, {
+            [instance.name]: instance
+          });
+    }
+
+    if (instance instanceof Mark) {
+      return this._marks[instance.name]
+        ? this._marks[instance.name]
+        : Object.assign(this._marks, {
+            [instance.name]: instance
+          });
+    }
+  }
+
+  addProsemirrorSchema(nodes, type) {
+    this.prosemirrorSchema[type] = Object.assign(
+      this.prosemirrorSchema[type],
+      nodes
+    );
+  }
+
+  getSchema() {
+    const nodes = DefaultSchema.nodes;
+    const marks = {};
+
+    for (let index in this._nodes) {
+      nodes[index] = this._nodes[index].toJSON();
+    }
+
+    for (let index in this._marks) {
+      marks[index] = this._marks[index].toJSON();
+    }
+
+    this.schema = new PmPschema({
+      nodes: Object.assign(nodes, this.prosemirrorSchema.nodes),
+      marks: Object.assign(marks, this.prosemirrorSchema.marks)
+    });
+    return this.schema;
+  }
+}
diff --git a/wax-prosemirror-services/src/SchemaService/SchemaService.js b/wax-prosemirror-services/src/SchemaService/SchemaService.js
new file mode 100644
index 0000000000000000000000000000000000000000..e530c3eb488cb64090e70e8bb29460aeae91dea5
--- /dev/null
+++ b/wax-prosemirror-services/src/SchemaService/SchemaService.js
@@ -0,0 +1,37 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Schema from "./Schema";
+import Node from "./Node";
+import Mark from "./Mark";
+
+export default class SchemaService extends Service {
+  name = "SchemaService";
+
+  register() {
+    this.container
+      .bind("Schema")
+      .to(Schema)
+      .inSingletonScope();
+
+    this.container.bind("CreateNode").toFactory(context => {
+      return (schema, options = { toWaxSchema: false }) => {
+        const schemaInstance = context.container.get("Schema");
+        if (options.toWaxSchema) {
+          schemaInstance.addNode(schema);
+        } else {
+          schemaInstance.addProsemirrorSchema(schema, "nodes");
+        }
+      };
+    });
+
+    this.container.bind("CreateMark").toFactory(context => {
+      return (schema, options = { toWaxSchema: false }) => {
+        const schemaInstance = context.container.get("Schema");
+        if (options.toWaxSchema) {
+          schemaInstance.addMark(schema);
+        } else {
+          schemaInstance.addProsemirrorSchema(schema, "marks");
+        }
+      };
+    });
+  }
+}
diff --git a/wax-prosemirror-core/src/config/classes/CreateShortCuts.js b/wax-prosemirror-services/src/ShortCutsService/ShortCuts.js
similarity index 74%
rename from wax-prosemirror-core/src/config/classes/CreateShortCuts.js
rename to wax-prosemirror-services/src/ShortCutsService/ShortCuts.js
index 98986fb1c11e1aebd17baa76ef4075454bcbb666..51eab2330339d7efa657c9830e2fa43e88512be5 100644
--- a/wax-prosemirror-core/src/config/classes/CreateShortCuts.js
+++ b/wax-prosemirror-services/src/ShortCutsService/ShortCuts.js
@@ -1,3 +1,4 @@
+import { injectable } from "inversify";
 import { keymap } from "prosemirror-keymap";
 import { undoInputRule } from "prosemirror-inputrules";
 import { undo, redo } from "prosemirror-history";
@@ -10,14 +11,15 @@ import {
   selectParentNode
 } from "prosemirror-commands";
 
-class CreateShortCuts {
-  constructor(config) {
-    this.schema = config.schema;
-    this.shortCuts = config.shortCuts;
-
+@injectable()
+class ShortCuts {
+  keys = {};
+  constructor(plugins, schema) {
     this.insertBreak = this.insertBreak.bind(this);
     this.insertRule = this.insertRule.bind(this);
-    return keymap(this.createKeyBindings());
+    this.PmPlugins = plugins;
+    this.schema = schema;
+    this.keys = this.getKeys();
   }
 
   insertBreak(state, dispatch) {
@@ -32,8 +34,18 @@ class CreateShortCuts {
     return true;
   }
 
+  createShortCuts() {
+    const shortCuts = keymap(this.createKeyBindings());
+    this.PmPlugins.add("shortcuts", shortCuts);
+  }
+
+  addShortCut(shortcut) {
+    this.keys = Object.assign(this.keys, shortcut);
+    this.createShortCuts();
+  }
+
   createKeyBindings() {
-    const keys = Object.assign(this.getKeys(), this.shortCuts);
+    const keys = this.keys;
     Object.keys(baseKeymap).forEach(key => {
       if (keys[key]) {
         keys[key] = chainCommands(keys[key], baseKeymap[key]);
@@ -63,4 +75,4 @@ class CreateShortCuts {
   }
 }
 
-export default CreateShortCuts;
+export default ShortCuts;
diff --git a/wax-prosemirror-services/src/ShortCutsService/ShortCutsService.js b/wax-prosemirror-services/src/ShortCutsService/ShortCutsService.js
new file mode 100644
index 0000000000000000000000000000000000000000..17a42b805f91de993b4f641caa5811ac35d32773
--- /dev/null
+++ b/wax-prosemirror-services/src/ShortCutsService/ShortCutsService.js
@@ -0,0 +1,23 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import ShortCuts from "./ShortCuts";
+
+export default class ShortCutsService extends Service {
+  name = "ShortCutsService";
+
+  boot() {
+    const shortCuts = this.container.get("ShortCuts");
+    shortCuts.createShortCuts();
+  }
+
+  register() {
+    const PmPlugins = this.app.PmPlugins;
+    this.container
+      .bind("ShortCuts")
+      .toDynamicValue(() => {
+        const { schema: { schema } } = this.app;
+
+        return new ShortCuts(PmPlugins, schema);
+      })
+      .inSingletonScope();
+  }
+}
diff --git a/wax-prosemirror-services/src/TablesService/EditTableService/EditTableService.js b/wax-prosemirror-services/src/TablesService/EditTableService/EditTableService.js
new file mode 100644
index 0000000000000000000000000000000000000000..969a3bad14c9259f514b3344d5575f76b413b7de
--- /dev/null
+++ b/wax-prosemirror-services/src/TablesService/EditTableService/EditTableService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import TableDropDownOptions from "./TableDropDownOptions";
+
+class EditTableService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("TableDropDownOptions").to(TableDropDownOptions);
+  }
+}
+
+export default EditTableService;
diff --git a/wax-prosemirror-services/src/TablesService/EditTableService/TableDropDownOptions.js b/wax-prosemirror-services/src/TablesService/EditTableService/TableDropDownOptions.js
new file mode 100644
index 0000000000000000000000000000000000000000..b9d317b1c0b2a86736872fde3aaa7aca24f3c942
--- /dev/null
+++ b/wax-prosemirror-services/src/TablesService/EditTableService/TableDropDownOptions.js
@@ -0,0 +1,37 @@
+import React from "react";
+import { v4 as uuid } from "uuid";
+import { injectable } from "inversify";
+import { isEmpty } from "lodash";
+import { TableDropDown } from "wax-prosemirror-components";
+import { addColumnBefore } from "prosemirror-tables";
+import { canInsert } from "../../lib/Utils";
+import Tools from "../../lib/Tools";
+
+@injectable()
+export default class TableDropDownOptions extends Tools {
+  title = "Select Options";
+  content = "table";
+
+  get run() {
+    return () => {
+      return true;
+    };
+  }
+
+  get enable() {
+    return state => {
+      return canInsert(state.config.schema.nodes.table)(state);
+    };
+  }
+
+  select(state) {
+    return addColumnBefore(state);
+  }
+
+  renderTool(view) {
+    if (isEmpty(view)) return null;
+    return this._isEnabled ? (
+      <TableDropDown key={uuid()} item={this.toJSON()} view={view} />
+    ) : null;
+  }
+}
diff --git a/wax-prosemirror-services/src/TablesService/InsertTableService/InsertTableService.js b/wax-prosemirror-services/src/TablesService/InsertTableService/InsertTableService.js
new file mode 100644
index 0000000000000000000000000000000000000000..ceee67bfb91541fb7028194bc9a397ab737a0aec
--- /dev/null
+++ b/wax-prosemirror-services/src/TablesService/InsertTableService/InsertTableService.js
@@ -0,0 +1,32 @@
+import { tableNodes } from "prosemirror-tables";
+import Service from "wax-prosemirror-core/src/services/Service";
+import Table from "./Table";
+
+class InsertTableService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Table").to(Table);
+
+    const { table, table_row, table_cell, table_header } = tableNodes({
+      tableGroup: "block",
+      cellContent: "block+"
+    });
+    const createNode = this.container.get("CreateNode");
+
+    createNode({
+      table
+    });
+    createNode({
+      table_row
+    });
+    createNode({
+      table_cell
+    });
+    createNode({
+      table_header
+    });
+  }
+}
+
+export default InsertTableService;
diff --git a/wax-prosemirror-services/src/TablesService/InsertTableService/Table.js b/wax-prosemirror-services/src/TablesService/InsertTableService/Table.js
new file mode 100644
index 0000000000000000000000000000000000000000..238c9084ecdb3ffc8cc4003598401d83db04685f
--- /dev/null
+++ b/wax-prosemirror-services/src/TablesService/InsertTableService/Table.js
@@ -0,0 +1,22 @@
+import Tools from "../../lib/Tools";
+import { createTable, canInsert } from "../../lib/Utils";
+import { injectable } from "inversify";
+import { icons } from "wax-prosemirror-components";
+
+@injectable()
+export default class Table extends Tools {
+  title = "Insert table";
+  content = icons.table;
+
+  get run() {
+    return (state, dispatch) => {
+      return createTable(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return canInsert(state.config.schema.nodes.table)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/TablesService/TablesService.js b/wax-prosemirror-services/src/TablesService/TablesService.js
new file mode 100644
index 0000000000000000000000000000000000000000..5d2805a7a241eb3750769c97bb5ef0f0286b7d0f
--- /dev/null
+++ b/wax-prosemirror-services/src/TablesService/TablesService.js
@@ -0,0 +1,10 @@
+import TablesServices from "./index";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class TablesService extends Service {
+  register() {
+    this.config.pushToArray("services", TablesServices);
+  }
+}
+
+export default TablesService;
diff --git a/wax-prosemirror-services/src/TablesService/index.js b/wax-prosemirror-services/src/TablesService/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..9565d0fbe0c9bab890a60a17c49de8ab53f42ca4
--- /dev/null
+++ b/wax-prosemirror-services/src/TablesService/index.js
@@ -0,0 +1,4 @@
+import InsertTableService from "./InsertTableService/InsertTableService";
+import EditTableService from "./EditTableService/EditTableService";
+
+export default [new InsertTableService(), new EditTableService()];
diff --git a/wax-prosemirror-services/src/TextBlockLevel/BlockQuoteService/BlockQuote.js b/wax-prosemirror-services/src/TextBlockLevel/BlockQuoteService/BlockQuote.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a9f9e17ae3f6b0aff608081ab8d91bfab1f67ca
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/BlockQuoteService/BlockQuote.js
@@ -0,0 +1,23 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { wrapIn } from "prosemirror-commands";
+
+@injectable()
+class BlockQuote extends Tools {
+  title = "Change to Block Quote";
+  content = "Block Quote";
+
+  get run() {
+    return (state, dispatch) => {
+      wrapIn(state.config.schema.nodes.blockquote)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      console.log(state);
+      return wrapIn(state.config.schema.nodes.blockquote)(state);
+    };
+  }
+}
+export default BlockQuote;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/BlockQuoteService/BlockQuoteService.js b/wax-prosemirror-services/src/TextBlockLevel/BlockQuoteService/BlockQuoteService.js
new file mode 100644
index 0000000000000000000000000000000000000000..b81a5f94c1d286a5f16f5a279de6bba0ffde3084
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/BlockQuoteService/BlockQuoteService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { blockQuoteNode } from "wax-prosemirror-schema";
+import BlockQuote from "./BlockQuote";
+
+class BlockQuoteService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("BlockQuote").to(BlockQuote);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        blockquote: blockQuoteNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default BlockQuoteService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ExtractPoetryService/ExtractPoetry.js b/wax-prosemirror-services/src/TextBlockLevel/ExtractPoetryService/ExtractPoetry.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3507f5d87bb4fdb95ed926d34ccb8bd9c2a1eba
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ExtractPoetryService/ExtractPoetry.js
@@ -0,0 +1,22 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+class ExtractPoetry extends Tools {
+  title = "Change to Extract Poetry";
+  content = "Extract Poetry";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.extractPoetry)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.extractPoetry)(state);
+    };
+  }
+}
+export default ExtractPoetry;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ExtractPoetryService/ExtractPoetryService.js b/wax-prosemirror-services/src/TextBlockLevel/ExtractPoetryService/ExtractPoetryService.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b0a043a08c75a58aaf1d3540b0b146ced763768
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ExtractPoetryService/ExtractPoetryService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { extractPoetryNode } from "wax-prosemirror-schema";
+import ExtractPoetry from "./ExtractPoetry";
+
+class ExtractPoetryService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("ExtractPoetry").to(ExtractPoetry);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        extractPoetry: extractPoetryNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default ExtractPoetryService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ExtractProseService/ExtractProse.js b/wax-prosemirror-services/src/TextBlockLevel/ExtractProseService/ExtractProse.js
new file mode 100644
index 0000000000000000000000000000000000000000..261cfe18de1fd51b7b63a0c5376a6fa338bfb281
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ExtractProseService/ExtractProse.js
@@ -0,0 +1,22 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+class ExtractProse extends Tools {
+  title = "Change to Extract Prose";
+  content = "Extract Prose";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.extractProse)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.extractProse)(state);
+    };
+  }
+}
+export default ExtractProse;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ExtractProseService/ExtractProseService.js b/wax-prosemirror-services/src/TextBlockLevel/ExtractProseService/ExtractProseService.js
new file mode 100644
index 0000000000000000000000000000000000000000..74933be551e9260694c2518de6d25ad335194e03
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ExtractProseService/ExtractProseService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { extractProseNode } from "wax-prosemirror-schema";
+import ExtractProse from "./ExtractProse";
+
+class ExtractProseService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("ExtractProse").to(ExtractProse);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        extractProse: extractProseNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default ExtractProseService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ParagraphContinuedService/ParagraphContinued.js b/wax-prosemirror-services/src/TextBlockLevel/ParagraphContinuedService/ParagraphContinued.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcc3c506e807d35422df6cf9fb47621c908c1575
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ParagraphContinuedService/ParagraphContinued.js
@@ -0,0 +1,23 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+class ParagraphContinued extends Tools {
+  title = "Change to Paragraph Continued";
+  content = "Paragraph Continued";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.paragraphCont)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.paragraphCont)(state);
+    };
+  }
+}
+
+export default ParagraphContinued;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ParagraphContinuedService/ParagraphContinuedService.js b/wax-prosemirror-services/src/TextBlockLevel/ParagraphContinuedService/ParagraphContinuedService.js
new file mode 100644
index 0000000000000000000000000000000000000000..dbb93a649076d611dfb88219f8544fdd20b9697c
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ParagraphContinuedService/ParagraphContinuedService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { paragraphContNode } from "wax-prosemirror-schema";
+import ParagraphContinued from "./ParagraphContinued";
+
+class ParagraphContinuedService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("ParagraphContinued").to(ParagraphContinued);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        paragraphCont: paragraphContNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default ParagraphContinuedService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ParagraphService/Paragraph.js b/wax-prosemirror-services/src/TextBlockLevel/ParagraphService/Paragraph.js
new file mode 100644
index 0000000000000000000000000000000000000000..b4480b8d9767db366ec8c4ba88dc87ee389bd8c4
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ParagraphService/Paragraph.js
@@ -0,0 +1,21 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+export default class Paragraph extends Tools {
+  title = "Change to Paragraph";
+  content = "Paragraph";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.paragraph)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.paragraph)(state);
+    };
+  }
+}
diff --git a/wax-prosemirror-services/src/TextBlockLevel/ParagraphService/ParagraphService.js b/wax-prosemirror-services/src/TextBlockLevel/ParagraphService/ParagraphService.js
new file mode 100644
index 0000000000000000000000000000000000000000..b02a73f210db858dc2ada728c00099e5f7d53ed2
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/ParagraphService/ParagraphService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Paragraph from "./Paragraph";
+
+class ParagraphService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("Paragraph").to(Paragraph);
+  }
+}
+
+export default ParagraphService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/SourceNoteService/SourceNote.js b/wax-prosemirror-services/src/TextBlockLevel/SourceNoteService/SourceNote.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e05eea06c5494e8ef41034841d395b82be6bbf5
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/SourceNoteService/SourceNote.js
@@ -0,0 +1,22 @@
+import Tools from "../../lib/Tools";
+import { injectable } from "inversify";
+import { setBlockType } from "prosemirror-commands";
+
+@injectable()
+class SourceNote extends Tools {
+  title = "Change to Source Note";
+  content = "Source Note";
+
+  get run() {
+    return (state, dispatch) => {
+      setBlockType(state.config.schema.nodes.sourceNote)(state, dispatch);
+    };
+  }
+
+  get enable() {
+    return state => {
+      return setBlockType(state.config.schema.nodes.sourceNote)(state);
+    };
+  }
+}
+export default SourceNote;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/SourceNoteService/SourceNoteService.js b/wax-prosemirror-services/src/TextBlockLevel/SourceNoteService/SourceNoteService.js
new file mode 100644
index 0000000000000000000000000000000000000000..f57ac2f927fcf006dc7cc97d61b3441728814413
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/SourceNoteService/SourceNoteService.js
@@ -0,0 +1,20 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { sourceNoteNode } from "wax-prosemirror-schema";
+import SourceNote from "./SourceNote";
+
+class SourceNoteService extends Service {
+  boot() {}
+
+  register() {
+    this.container.bind("SourceNote").to(SourceNote);
+    const createNode = this.container.get("CreateNode");
+    createNode(
+      {
+        sourceNote: sourceNoteNode
+      },
+      { toWaxSchema: true }
+    );
+  }
+}
+
+export default SourceNoteService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/TextBlockLevelService.js b/wax-prosemirror-services/src/TextBlockLevel/TextBlockLevelService.js
new file mode 100644
index 0000000000000000000000000000000000000000..88ce4ba44c49a602d32fa09f18f0255e413224ba
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/TextBlockLevelService.js
@@ -0,0 +1,10 @@
+import TextServices from "./index";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class TextBlockLevelService extends Service {
+  register() {
+    this.config.pushToArray("services", TextServices);
+  }
+}
+
+export default TextBlockLevelService;
diff --git a/wax-prosemirror-services/src/TextBlockLevel/index.js b/wax-prosemirror-services/src/TextBlockLevel/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7506441049eced9f65d37eb4a3e2a2b6fe2875be
--- /dev/null
+++ b/wax-prosemirror-services/src/TextBlockLevel/index.js
@@ -0,0 +1,15 @@
+import ExtractPoetryService from "./ExtractPoetryService/ExtractPoetryService";
+import ExtractProseService from "./ExtractProseService/ExtractProseService";
+import ParagraphContinuedService from "./ParagraphContinuedService/ParagraphContinuedService";
+import ParagraphService from "./ParagraphService/ParagraphService";
+import SourceNoteService from "./SourceNoteService/SourceNoteService";
+import BlockQuoteService from "./BlockQuoteService/BlockQuoteService";
+
+export default [
+  new ExtractPoetryService(),
+  new ExtractProseService(),
+  new ParagraphContinuedService(),
+  new ParagraphService(),
+  new SourceNoteService(),
+  new BlockQuoteService()
+];
diff --git a/wax-prosemirror-services/src/TrackChangeService/TrackChangeService.js b/wax-prosemirror-services/src/TrackChangeService/TrackChangeService.js
new file mode 100644
index 0000000000000000000000000000000000000000..b2bdc49c462839f88c525b0522e752c7677d5765
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/TrackChangeService.js
@@ -0,0 +1,28 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import { trackChangesMarks, trackChangesNodes } from "wax-prosemirror-schema";
+
+class TrackChangeService extends Service {
+  boot() {}
+
+  register() {
+    const createMark = this.container.get("CreateMark");
+    const createNode = this.container.get("CreateNode");
+
+    Object.keys(trackChangesMarks).forEach(mark => {
+      createMark({
+        [mark]: trackChangesMarks[mark]
+      });
+    });
+
+    Object.keys(trackChangesNodes).forEach(node => {
+      createNode(
+        {
+          [node]: trackChangesNodes[node]
+        },
+        { toWaxSchema: true }
+      );
+    });
+  }
+}
+
+export default TrackChangeService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/AnnotationToolGroupService/AnnotationToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/AnnotationToolGroupService/AnnotationToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d335bed09addf988cf8cb09a3e994644ca926ee
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/AnnotationToolGroupService/AnnotationToolGroupService.js
@@ -0,0 +1,12 @@
+import Service from "wax-prosemirror-core/src/services/Service";
+import Annotations from "./Annotations";
+
+class AnnotationToolGroupService extends Service {
+  name = "AnnotationToolGroupService";
+
+  register() {
+    this.container.bind("Annotations").to(Annotations);
+  }
+}
+
+export default AnnotationToolGroupService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/AnnotationToolGroupService/Annotations.js b/wax-prosemirror-services/src/WaxToolGroups/AnnotationToolGroupService/Annotations.js
new file mode 100644
index 0000000000000000000000000000000000000000..baebfef1670007da16ba30465c27fc5beab40a65
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/AnnotationToolGroupService/Annotations.js
@@ -0,0 +1,36 @@
+import { injectable, inject } from "inversify";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Annotations extends ToolGroup {
+  tools = [];
+  constructor(
+    @inject("Code") code,
+    @inject("Emphasis") emphasis,
+    @inject("Link") link,
+    @inject("SmallCaps") smallcaps,
+    @inject("StrikeThrough") strikethrough,
+    @inject("Strong") strong,
+    @inject("Subscript") subscript,
+    @inject("Superscript") superscript,
+    @inject("Underline") underline
+  ) {
+    super();
+    smallcaps.hideOnToolbar = true;
+    subscript.hideOnToolbar = true;
+    superscript.hideOnToolbar = true;
+    this.tools = [
+      strong,
+      emphasis,
+      code,
+      link,
+      strikethrough,
+      underline,
+      smallcaps,
+      subscript,
+      superscript
+    ];
+  }
+}
+
+export default Annotations;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/BaseToolGroupService/Base.js b/wax-prosemirror-services/src/WaxToolGroups/BaseToolGroupService/Base.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b3e2c89dc170ee0d6ee2f16004910bfadb0a5de
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/BaseToolGroupService/Base.js
@@ -0,0 +1,17 @@
+import { injectable, inject } from "inversify";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Base extends ToolGroup {
+  tools = [];
+  constructor(
+    @inject("Undo") undo,
+    @inject("Redo") redo,
+    @inject("Note") note
+  ) {
+    super();
+    this.tools = [undo, redo, note];
+  }
+}
+
+export default Base;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/BaseToolGroupService/BaseToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/BaseToolGroupService/BaseToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..90b532f0f93e476bbf0e377efa0e67777bff36ed
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/BaseToolGroupService/BaseToolGroupService.js
@@ -0,0 +1,12 @@
+import Base from "./Base";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class BaseToolGroupService extends Service {
+  name = "BaseToolGroupService";
+
+  register() {
+    this.container.bind("Base").to(Base);
+  }
+}
+
+export default BaseToolGroupService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/DisplayToolGroupService/Display.js b/wax-prosemirror-services/src/WaxToolGroups/DisplayToolGroupService/Display.js
new file mode 100644
index 0000000000000000000000000000000000000000..60b888079cbf5c6a995142cde9d996a929f65a97
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/DisplayToolGroupService/Display.js
@@ -0,0 +1,35 @@
+import React from "react";
+import { injectable, inject } from "inversify";
+import { LeftMenuTitle } from "wax-prosemirror-components";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Display extends ToolGroup {
+  tools = [];
+  title = <LeftMenuTitle title="Display" />;
+
+  constructor(
+    @inject("Author") author,
+    @inject("Title") title,
+    @inject("SubTitle") subtitle,
+    @inject("EpigraphProse") epigraphprose,
+    @inject("EpigraphPoetry") epigraphpoetry,
+    @inject("Heading1") heading1,
+    @inject("Heading2") heading2,
+    @inject("Heading3") heading3
+  ) {
+    super();
+    this.tools = [
+      title,
+      author,
+      subtitle,
+      epigraphprose,
+      epigraphpoetry,
+      heading1,
+      heading2,
+      heading3
+    ];
+  }
+}
+
+export default Display;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/DisplayToolGroupService/DisplayToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/DisplayToolGroupService/DisplayToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..a2a4c84fdd282bf4524272955a1337dcf7a7cb8c
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/DisplayToolGroupService/DisplayToolGroupService.js
@@ -0,0 +1,12 @@
+import Display from "./Display";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class DisplayToolGroupService extends Service {
+  name = "DisplayToolGroupService";
+
+  register() {
+    this.container.bind("Display").to(Display);
+  }
+}
+
+export default DisplayToolGroupService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/ImageToolGroupService/ImageToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/ImageToolGroupService/ImageToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..4e5c2f132466159638c5c031642511b884f96f3c
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/ImageToolGroupService/ImageToolGroupService.js
@@ -0,0 +1,12 @@
+import Images from "./Images";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class ImageToolGroupService extends Service {
+  name = "ImageToolGroupService";
+
+  register() {
+    this.container.bind("Images").to(Images);
+  }
+}
+
+export default ImageToolGroupService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/ImageToolGroupService/Images.js b/wax-prosemirror-services/src/WaxToolGroups/ImageToolGroupService/Images.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f6b397a683db2ad9e31d76bbf38e13e660561a1
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/ImageToolGroupService/Images.js
@@ -0,0 +1,13 @@
+import { injectable, inject } from "inversify";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Images extends ToolGroup {
+  tools = [];
+  constructor(@inject("Image") image) {
+    super();
+    this.tools = [image];
+  }
+}
+
+export default Images;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/ListToolGroupService/ListToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/ListToolGroupService/ListToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..311f02da644b59a37fc7310dc488dbc2be870851
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/ListToolGroupService/ListToolGroupService.js
@@ -0,0 +1,12 @@
+import Lists from "./Lists";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class ListToolGroupService extends Service {
+  name = "ListToolGroupService";
+
+  register() {
+    this.container.bind("Lists").to(Lists);
+  }
+}
+
+export default ListToolGroupService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/ListToolGroupService/Lists.js b/wax-prosemirror-services/src/WaxToolGroups/ListToolGroupService/Lists.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d0a9674a84b3a57167300ed51517ccf5865c922
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/ListToolGroupService/Lists.js
@@ -0,0 +1,18 @@
+import { injectable, inject } from "inversify";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Lists extends ToolGroup {
+  tools = [];
+  constructor(
+    @inject("OrderedList") orderedlist,
+    @inject("BulletList") bulletlist,
+    @inject("JoinUp") joinup,
+    @inject("Lift") lift
+  ) {
+    super();
+    this.tools = [orderedlist, bulletlist, joinup, lift];
+  }
+}
+
+export default Lists;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/TableToolGroupService/TableToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/TableToolGroupService/TableToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..10c19d7df52183acb6f200021d6b7e65c5199eb7
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/TableToolGroupService/TableToolGroupService.js
@@ -0,0 +1,12 @@
+import Tables from "./Tables";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class TableToolGroupService extends Service {
+  name = "TableToolGroupService";
+
+  register() {
+    this.container.bind("Tables").to(Tables);
+  }
+}
+
+export default TableToolGroupService;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/TableToolGroupService/Tables.js b/wax-prosemirror-services/src/WaxToolGroups/TableToolGroupService/Tables.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6719878a408aa708d654adc17e65a9634e7d8cf
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/TableToolGroupService/Tables.js
@@ -0,0 +1,16 @@
+import { injectable, inject } from "inversify";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Tables extends ToolGroup {
+  tools = [];
+  constructor(
+    @inject("Table") table,
+    @inject("TableDropDownOptions") tableDropDownOptions
+  ) {
+    super();
+    this.tools = [table, tableDropDownOptions];
+  }
+}
+
+export default Tables;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/TextToolGroupService/Text.js b/wax-prosemirror-services/src/WaxToolGroups/TextToolGroupService/Text.js
new file mode 100644
index 0000000000000000000000000000000000000000..c09c5a0f000ca50f0f4d4a32806fbd00a53e392b
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/TextToolGroupService/Text.js
@@ -0,0 +1,31 @@
+import React from "react";
+import { injectable, inject } from "inversify";
+import { LeftMenuTitle } from "wax-prosemirror-components";
+import ToolGroup from "../../lib/ToolGroup";
+
+@injectable()
+class Text extends ToolGroup {
+  tools = [];
+  title = <LeftMenuTitle title="Text" />;
+
+  constructor(
+    @inject("Paragraph") paragraph,
+    @inject("ParagraphContinued") paragraphContinued,
+    @inject("ExtractProse") extractProse,
+    @inject("ExtractPoetry") extractPoetry,
+    @inject("SourceNote") sourceNote,
+    @inject("BlockQuote") blockQuote
+  ) {
+    super();
+    this.tools = [
+      paragraph,
+      paragraphContinued,
+      extractProse,
+      extractPoetry,
+      sourceNote,
+      blockQuote
+    ];
+  }
+}
+
+export default Text;
diff --git a/wax-prosemirror-services/src/WaxToolGroups/TextToolGroupService/TextToolGroupService.js b/wax-prosemirror-services/src/WaxToolGroups/TextToolGroupService/TextToolGroupService.js
new file mode 100644
index 0000000000000000000000000000000000000000..80f34a2fc2f9660e8bbf32ab30a85b0f2118f18d
--- /dev/null
+++ b/wax-prosemirror-services/src/WaxToolGroups/TextToolGroupService/TextToolGroupService.js
@@ -0,0 +1,12 @@
+import Text from "./Text";
+import Service from "wax-prosemirror-core/src/services/Service";
+
+class TextToolGroupService extends Service {
+  name = "TextToolGroupService";
+
+  register() {
+    this.container.bind("Text").to(Text);
+  }
+}
+
+export default TextToolGroupService;
diff --git a/wax-prosemirror-services/src/lib/Middleware.js b/wax-prosemirror-services/src/lib/Middleware.js
new file mode 100644
index 0000000000000000000000000000000000000000..25e8831120deacbd087d9e3eb371bf7a0f743c33
--- /dev/null
+++ b/wax-prosemirror-services/src/lib/Middleware.js
@@ -0,0 +1,33 @@
+export default class Middleware {
+  constructor() {
+    // Array prototype last
+    if (!Array.prototype.last) {
+      Array.prototype.last = function() {
+        return this[this.length - 1];
+      };
+    }
+
+    // Array prototype reduceOneRight
+    if (!Array.prototype.reduceOneRight) {
+      Array.prototype.reduceOneRight = function() {
+        return this.slice(0, -1);
+      };
+    }
+  }
+
+  use(fn) {
+    this.go = (stack => (...args) =>
+      stack(...args.reduceOneRight(), () => {
+        let _next = args.last();
+        fn.apply(this, [
+          ...args.reduceOneRight(),
+          _next.bind.apply(_next, [null, ...args.reduceOneRight()])
+        ]);
+      }))(this.go);
+  }
+
+  go(...args) {
+    let _next = args.last();
+    _next.apply(this, args.reduceOneRight());
+  }
+}
diff --git a/wax-prosemirror-services/src/lib/ToolGroup.js b/wax-prosemirror-services/src/lib/ToolGroup.js
new file mode 100644
index 0000000000000000000000000000000000000000..1340e666f8fbfa0e1ae2f9bc57302b2fde3060ea
--- /dev/null
+++ b/wax-prosemirror-services/src/lib/ToolGroup.js
@@ -0,0 +1,83 @@
+import React, { useState } from "react";
+import { injectable } from "inversify";
+import { isFunction } from "lodash";
+@injectable()
+export default class ToolGroup {
+  _config = {};
+  title = "";
+  _tools = [];
+  constructor() {}
+  setGroupConfig(config) {
+    this._config = config;
+  }
+
+  excludeIncludeTools() {
+    const { exclude = [], include = [] } = this._config;
+
+    if (include.length > 0) {
+      this._tools.map(tool => {
+        if (include.includes(tool.constructor.name)) {
+          tool.enableTool();
+        } else {
+          tool.disableTool();
+        }
+      });
+    } else {
+      this._tools.map(tool => {
+        if (exclude.includes(tool.constructor.name)) {
+          tool.disableTool();
+        }
+      });
+    }
+  }
+
+  set tools(tools) {
+    this._tools = tools;
+    for (var i in this._tools) {
+      if (this._tools[i].hideOnToolbar) {
+        this._tools.push(this._tools.splice(i, 1)[0]);
+      }
+    }
+  }
+
+  renderTools(view) {
+    const [more, showHide] = useState(false);
+    const tools = [];
+    const rest = [];
+    this._tools.forEach(tool => {
+      if (tool.hideOnToolbar) {
+        rest.push(tool.renderTool(view));
+      } else {
+        tools.push(tool.renderTool(view));
+      }
+    });
+
+    const Title = isFunction(this.title) ? this.title : () => this.title;
+
+    return (
+      <div key={`groupName-${this.constructor.name}`}>
+        <Title />
+        {tools}
+        {rest.length && !more ? (
+          <button onClick={() => showHide(!more)}>...</button>
+        ) : null}
+        {more && (
+          <div>
+            <button onClick={() => showHide(!more)}>...</button>
+            <div
+              style={{
+                display: "flex",
+                width: "0",
+                top: "40px",
+                position: "relative",
+                right: "100%"
+              }}
+            >
+              {rest}
+            </div>
+          </div>
+        )}
+      </div>
+    );
+  }
+}
diff --git a/wax-prosemirror-services/src/lib/Tools.js b/wax-prosemirror-services/src/lib/Tools.js
new file mode 100644
index 0000000000000000000000000000000000000000..befa3bb109e96d6c5218b2eb1c2dfd4bf33775ef
--- /dev/null
+++ b/wax-prosemirror-services/src/lib/Tools.js
@@ -0,0 +1,63 @@
+import React from "react";
+import { v4 as uuid } from "uuid";
+import { isEmpty } from "lodash";
+import { injectable, inject } from "inversify";
+import { Button } from "wax-prosemirror-components";
+
+@injectable()
+export default class Tools {
+  title = "title";
+  content = "content";
+  _isEnabled = true;
+  hideOnToolbar = false;
+  config = {};
+  pmplugins = {};
+
+  constructor(@inject("Config") config, @inject("PmPlugins") pmplugins) {
+    this.config = config;
+    this.pmplugins = pmplugins;
+  }
+
+  get run() {
+    return true;
+  }
+
+  get enable() {
+    return () => true;
+  }
+
+  select() {
+    return () => true;
+  }
+
+  get active() {
+    return () => false;
+  }
+
+  toJSON() {
+    return {
+      title: this.title,
+      content: this.content,
+      active: this.active,
+      run: this.run,
+      enable: this.enable,
+      select: this.select
+    };
+  }
+
+  renderTool(view) {
+    if (isEmpty(view)) return null;
+
+    return this._isEnabled ? (
+      <Button key={uuid()} item={this.toJSON()} view={view} />
+    ) : null;
+  }
+
+  disableTool() {
+    this._isEnabled = false;
+  }
+
+  enableTool() {
+    this._isEnabled = true;
+  }
+}
diff --git a/wax-prosemirror-components/src/mainMenuBar/MainMenuCommands.js b/wax-prosemirror-services/src/lib/Utils.js
similarity index 66%
rename from wax-prosemirror-components/src/mainMenuBar/MainMenuCommands.js
rename to wax-prosemirror-services/src/lib/Utils.js
index ab7f1da0a7d2d652672ef4f784aa6587ad3a39d2..ba2fcf3e5763d746fac41b6577f9e674a88d6312 100644
--- a/wax-prosemirror-components/src/mainMenuBar/MainMenuCommands.js
+++ b/wax-prosemirror-services/src/lib/Utils.js
@@ -30,6 +30,29 @@ const canInsert = type => state => {
   return false;
 };
 
+const getMarkPosition = ($start, mark) => {
+  let startIndex = $start.index(),
+    endIndex = $start.indexAfter();
+  while (
+    startIndex > 0 &&
+    mark.isInSet($start.parent.child(startIndex - 1).marks)
+  )
+    startIndex--;
+  while (
+    endIndex < $start.parent.childCount &&
+    mark.isInSet($start.parent.child(endIndex).marks)
+  )
+    endIndex++;
+  let startPos = $start.start(),
+    endPos = startPos;
+  for (let i = 0; i < endIndex; i++) {
+    let size = $start.parent.child(i).nodeSize;
+    if (i < startIndex) startPos += size;
+    endPos += size;
+  }
+  return { from: startPos, to: endPos };
+};
+
 const promptForURL = () => {
   let url = window && window.prompt("Enter the URL", "https://");
 
@@ -58,4 +81,11 @@ const createTable = (state, dispatch) => {
   dispatch(state.tr.replaceSelectionWith(table));
 };
 
-export { markActive, blockActive, canInsert, promptForURL, createTable };
+export {
+  markActive,
+  blockActive,
+  canInsert,
+  promptForURL,
+  createTable,
+  getMarkPosition
+};
diff --git a/wax-prosemirror-utilities/src/schema/SchemaHelpers.js b/wax-prosemirror-utilities/src/schema/SchemaHelpers.js
new file mode 100644
index 0000000000000000000000000000000000000000..3020008e105df94bfb17663ceb35334c02fe3e97
--- /dev/null
+++ b/wax-prosemirror-utilities/src/schema/SchemaHelpers.js
@@ -0,0 +1,50 @@
+const parseFormatList = str => {
+  if (!str) {
+    return [];
+  }
+  let formatList;
+  try {
+    formatList = JSON.parse(str);
+  } catch (error) {
+    return [];
+  }
+  if (!Array.isArray(formatList)) {
+    return [];
+  }
+  return formatList.filter(format => typeof format === "string"); // ensure there are only strings in list
+};
+
+const parseTracks = str => {
+  if (!str) {
+    return [];
+  }
+  let tracks;
+  try {
+    tracks = JSON.parse(str);
+  } catch (error) {
+    return [];
+  }
+  if (!Array.isArray(tracks)) {
+    return [];
+  }
+  return tracks.filter(
+    (
+      track // ensure required fields are present
+    ) =>
+      track.hasOwnProperty("user") &&
+      track.hasOwnProperty("username") &&
+      track.hasOwnProperty("date")
+  );
+};
+
+const blockLevelToDOM = node => {
+  const attrs = node.attrs.track.length
+    ? {
+        class: node.attrs.class,
+        "data-track": JSON.stringify(node.attrs.track)
+      }
+    : { class: node.attrs.class };
+  return attrs;
+};
+
+export { parseFormatList, parseTracks, blockLevelToDOM };