+ );
+ }
+}
+
+export default useFilters( [ 'woodash.example', 'woodash.example2' ] )( Dashboard );
diff --git a/plugins/woocommerce-admin/js/src/dashboard/style.scss b/plugins/woocommerce-admin/js/src/dashboard/style.scss
new file mode 100644
index 00000000000..3527a3714bf
--- /dev/null
+++ b/plugins/woocommerce-admin/js/src/dashboard/style.scss
@@ -0,0 +1,12 @@
+.wd_widget {
+ display: flex;
+ background: white;
+ border: 1px solid rgba( black, 0.2 );
+ padding: 2em;
+ align-items: center;
+ text-align: center;
+}
+
+.wd_widget-item {
+ flex: 1;
+}
diff --git a/plugins/woocommerce-admin/js/src/index.js b/plugins/woocommerce-admin/js/src/index.js
index 572bb9f62b4..5b49d85b0f2 100644
--- a/plugins/woocommerce-admin/js/src/index.js
+++ b/plugins/woocommerce-admin/js/src/index.js
@@ -1,3 +1,28 @@
-document.addEventListener( 'DOMContentLoaded', function() {
- console.log( 'hi!' );
-} );
+/** @format */
+/**
+ * External dependencies
+ */
+import { createElement, render } from '@wordpress/element';
+import { addFilter } from '@wordpress/hooks';
+
+/**
+ * Internal dependencies
+ */
+import Dashboard from './dashboard';
+
+render(
+ createElement( Dashboard ),
+ document.getElementById( 'root' )
+);
+
+setTimeout( function() {
+ function editText( string ) {
+ return `Also filtered: ${ string }`;
+ }
+ addFilter( 'woodash.example', 'editText', editText );
+}, 1500 );
+
+function editText2( string ) {
+ return `Filtered: ${ string }`;
+}
+addFilter( 'woodash.example2', 'editText2', editText2 );
diff --git a/plugins/woocommerce-admin/js/src/use-filters/index.js b/plugins/woocommerce-admin/js/src/use-filters/index.js
new file mode 100644
index 00000000000..419d2b9d22d
--- /dev/null
+++ b/plugins/woocommerce-admin/js/src/use-filters/index.js
@@ -0,0 +1,64 @@
+/**
+ * External dependencies
+ */
+import { debounce, isArray, uniqueId } from 'lodash';
+
+/**
+ * WordPress dependencies
+ */
+import { Component } from '@wordpress/element';
+import { addAction, removeAction } from '@wordpress/hooks';
+
+const ANIMATION_FRAME_PERIOD = 16;
+
+/**
+ * Creates a higher-order component which adds filtering capability to the
+ * wrapped component. Filters get applied when the original component is about
+ * to be mounted. When a filter is added or removed that matches the hook name,
+ * the wrapped component re-renders.
+ *
+ * @param {string|array} hookName Hook names exposed to be used by filters.
+ *
+ * @return {Function} Higher-order component factory.
+ */
+export default function useFilters( hookName ) {
+ const hookNames = isArray( hookName ) ? hookName : [ hookName ];
+
+ return function( OriginalComponent ) {
+ return class FilteredComponent extends Component {
+ constructor( props ) {
+ super( props );
+
+ this.onHooksUpdated = this.onHooksUpdated.bind( this );
+ this.namespace = uniqueId( 'woo-dash/use-filters/component-' );
+ this.throttledForceUpdate = debounce( () => {
+ this.forceUpdate();
+ }, ANIMATION_FRAME_PERIOD );
+
+ addAction( 'hookRemoved', this.namespace, this.onHooksUpdated );
+ addAction( 'hookAdded', this.namespace, this.onHooksUpdated );
+ }
+
+ componentWillUnmount() {
+ this.throttledForceUpdate.cancel();
+ removeAction( 'hookRemoved', this.namespace );
+ removeAction( 'hookAdded', this.namespace );
+ }
+
+ /**
+ * When a filter is added or removed for any matching hook name, the wrapped component should re-render.
+ *
+ * @param {string} updatedHookName Name of the hook that was updated.
+ */
+ onHooksUpdated( updatedHookName ) {
+ if ( -1 !== hookNames.indexOf( updatedHookName ) ) {
+ this.throttledForceUpdate();
+ }
+ }
+
+ render() {
+ return ;
+ }
+ };
+ };
+}
diff --git a/plugins/woocommerce-admin/lib/admin.php b/plugins/woocommerce-admin/lib/admin.php
new file mode 100644
index 00000000000..a54927f5659
--- /dev/null
+++ b/plugins/woocommerce-admin/lib/admin.php
@@ -0,0 +1,42 @@
+
+
+
+
+
+` in your templates
-
-== Frequently Asked Questions ==
-
-= A question that someone might have =
-
-An answer to that question.
-
-= What about foo bar? =
-
-Answer to foo bar dilemma.
-
-== Screenshots ==
-
-1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from
-the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets
-directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png`
-(or jpg, jpeg, gif).
-2. This is the second screen shot
-
-== Changelog ==
-
-= 1.0 =
-* A change since the previous version.
-* Another change.
-
-= 0.5 =
-* List versions from most recent at top to oldest at bottom.
-
-== Upgrade Notice ==
-
-= 1.0 =
-Upgrade notices describe the reason a user should upgrade. No more than 300 characters.
-
-= 0.5 =
-This version fixes a security related bug. Upgrade immediately.
-
-== Arbitrary section ==
-
-You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated
-plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or
-"installation." Arbitrary sections will be shown below the built-in sections outlined above.
-
-== A brief Markdown Example ==
-
-Ordered list:
-
-1. Some feature
-1. Another feature
-1. Something else about the plugin
-
-Unordered list:
-
-* something
-* something else
-* third thing
-
-Here's a link to [WordPress](https://wordpress.org/ "Your favorite software") and one to [Markdown's Syntax Documentation][markdown syntax].
-Titles are optional, naturally.
-
-[markdown syntax]: https://daringfireball.net/projects/markdown/syntax
- "Markdown is what the parser uses to process much of the readme file"
-
-Markdown uses email style notation for blockquotes and I've been told:
-> Asterisks for *emphasis*. Double it up for **strong**.
-
-``
diff --git a/plugins/woocommerce-admin/webpack.config.js b/plugins/woocommerce-admin/webpack.config.js
index 37b0d89dcfb..1975f0000b0 100644
--- a/plugins/woocommerce-admin/webpack.config.js
+++ b/plugins/woocommerce-admin/webpack.config.js
@@ -43,7 +43,6 @@ const externals = {
tinymce: 'tinymce',
moment: 'moment',
jquery: 'jQuery',
- lodash: 'lodash',
};
coreGlobals.forEach( ( name ) => {
@@ -58,7 +57,7 @@ const webpackConfig = {
output: {
path: path.resolve( 'js' ),
filename: 'index.js',
- library: [ 'wp', '[name]' ],
+ library: [ 'wp', 'woodash' ],
libraryTarget: 'this',
},
externals,
@@ -83,4 +82,8 @@ const webpackConfig = {
],
};
+if ( webpackConfig.mode !== 'production' ) {
+ webpackConfig.devtool = process.env.SOURCEMAP || 'source-map';
+}
+
module.exports = webpackConfig;
diff --git a/plugins/woocommerce-admin/woo-dash.php b/plugins/woocommerce-admin/woo-dash.php
index f176f007743..2038c4f459d 100755
--- a/plugins/woocommerce-admin/woo-dash.php
+++ b/plugins/woocommerce-admin/woo-dash.php
@@ -1,15 +1,28 @@