Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data Module: Expose state using selectors #4105

Merged
merged 8 commits into from
Jan 17, 2018

Conversation

youknowriad
Copy link
Contributor

@youknowriad youknowriad commented Dec 20, 2017

This is a POC, alternative to #4083 closes #2473

So the idea here is that a module that wants to expose a specific part of its state registers a set of selectors a consumer can access using the query Higher Order Component and the select helper passed as an argument. (This Higher Order Component could be written differently by wrapping each selector, It doesn't change the implementation a lot, I thought this want avoids creating these "unnecessary functions")

And a query Higher Order Component is also exposed to fetch data like so:

import { query } from '@wordpress/data';
const MyComponentWithData = query( ( select ) => {
	return {
		title: select( 'core/editor', 'getEditedPostTitle' ),
	};
} )( props =>
  <div>{ props.title || 'no title' }</div>
);

@youknowriad
Copy link
Contributor Author

cc @atimmer

data/index.js Outdated
}

export const query = ( mapPropsToSelectors ) => ( WrappedComponent ) => {
return connect( ( state ) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to pass ownProps here.

@gziolo
Copy link
Member

gziolo commented Dec 20, 2017

I was thinking about having along those lines:

import { query } from '@wordpress/data';

const MyComponent = props => <div>{ props.title || 'no title' } { props.description || '' }</div>;

const MyComponentWithEditorData= query( 'core/editor', ( select, ownProps ) => {
	return {
		title: select( 'getEditedPostTitle', ownProps.id ),
	};
} )( MyComponent );

const MyComponentWithEditorAndPluginData= query( 'plugin/details', ( select, ownProps ) => {
	return {
		description: select( 'getEditedPostDescription', ownProps.id ),
	};
} )( MyComponent );

This means more typing, but it allows to take advantage of the fact that listeners are scoped to namespaces with the recently merged PR #4058. I don't know the underling implementation of connect but I assume it is triggered every time global state changes, which wouldn't take advantage of the recently introduces optimizations. This is something that needs to be investigated. I'm skeptical that this boilerplate is better than what @youknowriad originally proposed, but I wanted to make sure we take the aforementioned point into account :)

@gziolo
Copy link
Member

gziolo commented Dec 20, 2017

Overall, I like what's proposed in this PR and would be happy to use it for plugin development. I like it more over GraphQL proposal only because I know this pattern well. Please keep in mind that I have zero GraphQL experience so I'm biased 😄

loadAndPersist( store, 'preferences', STORAGE_KEY, PREFERENCES_DEFAULTS );
enhanceWithBrowserSize( store );

registerSelectors( MODULE_KEY, { getEditedPostTitle } );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume we could use the following:

import * as selectors from './selectors';

registerSelectors( MODULE_KEY, selectors );

We would have to try it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to expose all selectors. Some are internal only.

@youknowriad
Copy link
Contributor Author

@gziolo yep, your API proposal doesn’t allow to get data from several modules/plugins at the same time, you can still query twice. I don’t know if this would be common but that’s why I avoided it at first

@mcsf
Copy link
Contributor

mcsf commented Dec 20, 2017

Overall, I like what's proposed in this PR and would be happy to use it for plugin development. I like it more over GraphQL proposal only because I know this pattern well. Please keep in mind that I have zero GraphQL experience so I'm biased 😄

I share @gziolo's bias (not enough experience in GraphQL, and a perception that it's not a necessary pattern if something like this here is possible). :) I like what's here.

I also second his suggestion to split the use of query by reducer. Using our common patterns in Gutenberg, that would look like:

// or: "selectEditorData"
const applyConnectEditor = query( 'core/editor',  );

const applyConnectPlugin = query(  );

export default flowRight( [
  applyConnectEditor,
  applyConnectPlugin,
] )( MyComponent );

Aside from the mere fact that it requires an author to think of the multitude of data sources (a benefit ipso facto), it allows better introspection than the more dynamic query( select => ( { foos: select( 'core/editor', 'getFoos' ) } ) ). Validators could look at the query source, warnings could be issued, dependency graphs could be inferred.

@youknowriad
Copy link
Contributor Author

youknowriad commented Dec 20, 2017

@mcsf @gziolo What about discoverability? How do you solve it with this approach, a "consumer" would have to know the selectors exposed from all the modules to be able to use them while he can just navigate GraphiQL to discover the available data? Also, what about the external API:

export default query( `{ 
 editor{ post { title } }
 yoast { keywords }
}`)( MyComponent )
const applyConnectEditor = query( 'core/editor', ( select ) => ( {
  title: select( 'getEditedPostTitle' )
} ) );
const applyConnectYoast = query( 'yoast', ( select ) => ( {
  keywords: select( 'getKeywords' )
} ) );

export default flowRight( [
  applyConnectEditor,
  applyConnectYoast,
] )( MyComponent );

Don't you think the external API is cleaner in GraphQL and corresponds exactly to the "data" requirements of the component?

@youknowriad
Copy link
Contributor Author

youknowriad commented Dec 20, 2017

Also, I think the same way "React" just by its name can create barriers to developers unware of its API (just simple functions), hearing "GraphQL" can create some barriers. What if we try to forget it as it's an implementation detail and think of this:

export default query( `{ 
 editor{ post { title } }
 yoast { keywords }
}`)( MyComponent )

as just an API to declare data needs.

@mcsf
Copy link
Contributor

mcsf commented Dec 20, 2017

Adding to this discussion what we saw on Slack a couple of weeks ago, which is the idea that ES2015 Proxy could provide a more polished experience of the same approach:

const selectEditorData = query( 'core/editor', ( select ) => ( {
  title: select.getEditedPostTitle(),
  isPanelOpen: select.isEditorSidebarPanelOpen( 'post-taxonomies' ),
} ) );

Here's a jsfiddle that would implement this. Now, Proxy isn't ready for primetime, and we could either polyfill it, or address this some other way if we deem this experience nice enough.


What about discoverability? How do you solve it with this approach, a "consumer" would have to know the selectors exposed from all the modules to be able to use them while he can just navigate GraphiQL to discover the available data? Also, what about the external API:

That GrQL example is pretty nice :D, but — however terse and clean it looks — there would still be an issue of knowing what the possible entities, fields and hierarchies are, no? Selectors IMO have the advantage of being more tangible, i.e. more recognizable (for most consumers) artefacts in code to look for. For both approaches there are means to automatically gather query/selector documentation (cf. Calypso devdocs); the main challenge is making all that visible to authors.

@mcsf
Copy link
Contributor

mcsf commented Dec 20, 2017

Don't you think the external API is cleaner in GraphQL and corresponds exactly to the "data" requirements of the component?

Yes, hard to refute. :)

@mcsf
Copy link
Contributor

mcsf commented Dec 20, 2017

Don't you think the external API is cleaner in GraphQL and corresponds exactly to the "data" requirements of the component?

The downside is the experience for authors seeking to making their data sources available for consumption. Writing a selector is conceptually simpler than writing a resolver. In this sense, it's hard for me to consider GraphQL a nicer experience until we work on providing better defaults and good helpers for the most common use cases.

@youknowriad
Copy link
Contributor Author

here would still be an issue of knowing what the possible entities, fields and hierarchies are, no?

The answer is no, try http://graphql.org/swapi-graphql/ click the "Docs" above and see how to can drill down/up in the data tree

For both approaches there are means to automatically gather query/selector documentation (cf. Calypso devdocs); the main challenge is making all that visible to authors.

GraphQL is auto-documented, you can use GraphiQL without any additional effort. (http://graphql.org/swapi-graphql this is GraphiQL)

@gziolo
Copy link
Member

gziolo commented Dec 20, 2017

Out of curiosity, how can you pass own props to GraphQL? Like when you want for instance to get a block by uid or something similar. Do you need to express it as part of the query?

@youknowriad
Copy link
Contributor Author

youknowriad commented Dec 20, 2017

The downside is the experience for authors seeking to making their data sources available for consumption. Writing a selector is conceptually simpler than writing a resolver.

My experience with GraphQL is not very big and I think once you try it you quickly grasp the "resolvers", just a tree of functions. But it's true that it's still more complex than just registering the selectors. The question may be whether we want to optimize for consumption or for production?

@youknowriad
Copy link
Contributor Author

Out of curiosity, how can you pass own props to GraphQL? Like when you want for instance to get a block by uid or something similar. Do you need to express it as part of the query?

yes:

{ block( :id ) }

and provide variables in the second parameter of the query HoC. I encourage you to try some queries in the GraphiQL shared above. you can navigate the docs to see what query you could run.

@mcsf
Copy link
Contributor

mcsf commented Dec 20, 2017

click the "Docs" above and see how to can drill down/up in the data tree

I stand corrected. :)

My experience with GraphQL is not very big and I think once you try it you quickly grasp the "resolvers", just a tree of functions. But it's true that it's still more complex than just registering the selectors. The question maybe whether we want to optimize for consumption or for production?

Yes, @jorgefilipecosta and I were just discussing this. It sounds conceivable to provide some helpers to build schemas/resolvers from more selector-like functions, thinking of plugins with small state footprints for whom we can minimize the investment.

@jorgefilipecosta
Copy link
Member

jorgefilipecosta commented Dec 20, 2017

It looks like the GraphQL is very good for consumption. But it presents an overhead for exposing a simple selector. E.g: if I want to expose a simple counter, as @mcsf referred.
Maybe, we can have the best of both worlds, If we can present something that allows a simple way to expose basic selectors and handles the schema/resolver creation something along the lines of:

registerSelector(
	‘core/editor.post’,
	getEditedPostTitle,
 	{
		title: ‘String’
	},
       undefined //query parameters
);

Offcourse this would be limiting what GraphQL offers us and it would not be mandatory to use this, and maybe we would not use it for our core needs. But it would provide an answer for people needing to expose a very simple selector.

@atimmer
Copy link
Member

atimmer commented Dec 21, 2017

First off: I have never used GraphQL.

My first impressions of GraphQL, I find edges -> node a really weird syntax:

allFilms {
  edges {
    node {
      id
    }
  }
}

Can we avoid that in our local implementation? Or is this something 'native' to the language?

export default query( `{ 
 editor{ post { title } }
 yoast { keywords }
}`)( MyComponent )

I think this is really amazing. It is an elegant way of querying cross component/plugin.

I also like the fact that both these APIs are inherently asynchronous. The consumer of the data doesn't have to know if the data is already available, or if it needs to be requested from the server. This could give way to really transparent lazy loading in the future.

These are my first impressions. I will look further into this.

@youknowriad
Copy link
Contributor Author

I find edges -> node a really weird syntax:

Not sure I understand what you think is weird here? is it the fact than node is embeded in edges? I guess this is just a choice, you can flatten everything if you think it's better.

@atimmer
Copy link
Member

atimmer commented Dec 21, 2017

I understand it better after reading this article: https://dev-blog.apollodata.com/explaining-graphql-connections-c48b7c3d6976. I think we should really document this stuff well because it isn't obvious at first.

@jaswrks
Copy link
Contributor

jaswrks commented Dec 21, 2017

Just adding a 👍 for selectors. I like @youknowriad's approach to registering reducers, and building on that I like @mcsf 's proxy idea best for selectors — or just reorganizing so the below is possible.

And I see it being more convenient to pass the registered reducer to select().

const selectData = query( ( select, ownProps ) => ( {
  isMobile: select( 'core/browser' ).isMobile(),
  title: select( 'core/editor' ).getEditedPostTitle(),
  isPanelOpen: select( 'core/editor' ).isEditorSidebarPanelOpen( 'post-taxonomies' ),
} ) );

Gutenberg has been my first real-world experience with React, but I used GraphQL on a small project once. I love it as a server-side REST alternative (truly awesome, and totally worth it to define a schema for the models that it handles). Using it to define schemas in client-side code might get tedious though. I have limited experience, just seems like extra work to me.

Maybe discoverability comes from the selectors themselves; i.e., docBlocks, articles written about them, examples of their use, and describing the object models they return.

As someone who recently jumped into Gutenberg completely new, I think it would be awesome if, in the future, reducers and selectors were split up and placed into subdirectories. Such that each reducer (or set of reducers) is accompanied by its selectors. It looks like that's the way things are headed already — making it easier to import them in sets, to be wrapped by select().

@moorscode
Copy link
Contributor

Coming from a usability point of view I like to share my thoughts on using the different samples as a programmer. Note that I have been programming in React this year, but don't do it on a weekly basis at the moment, feeling this might provide a bit of distance in looking at the code.

Rename the query function in @wordpress/data

The way the code creates a component is to use the output of a query function.
This seem like something that could be made easier to understand by renaming the function to be used. Especially because query is also used in other aspects of the functionality.

As I understand it, what the function does is to inject the props into a new component and returning that component. The "querying" part is done in GraphQL or in functions configured somewhere else.

Breakdown of context/knowledge needed per example

Taking the GraphQL example

import gql from 'graphql-tag';
import { query } from '@wordpress/data';

const MY_QUERY = gql`query { editor { post { title } } }`;

const MyComponentWithData = query( MY_QUERY )( props => 
  <div>{ get( props.data, 'editor.post.title', 'no title' ) }</div>
);
  1. + Knowing how to use the backtick notation is not really important, the syntax is pretty self-explanatory with the query followed by the arguments.
  2. - Having to import from graphql-tag
  3. - query is used twice, but these are not the same thing.
  4. - Having to define the implementation of a query in a separate place disconnects from the retrieval of data, reducing context and increasing effort to understand what is happening.

Taking the selectors example

import { query } from '@wordpress/data';

const MyComponentWithData = query( ( select ) => {
	return {
		title: select( 'core/editor', 'getEditedPostTitle' ),
	};
} )( props =>
  <div>{ props.title || 'no title' }</div>
);
  1. + Defining the actual implementation of a data-point in context with building the component
  2. - I see is a lot of {}()=>; characters, this is scary because it feels that it is very specific what order things should be.
  3. - This also makes reading it very hard, because I don't instantly see what is passed to what or used as an argument. (Keep in mind that I don't code ES6 on a daily basis).

Syntax wise it's a big jungle of specific order and character use. For experienced developers this might be second nature, but for all other people it takes a lot of effort to make sense of it all.

  1. - Having to know that there is a core/editor instead of a post where the data has to come from feels like the different way around.
  2. - Having to know the getEditedPostTitle function and using it in a string seems very specific and contextually hard.
  3. - Why is it called edited post title? Having to use this specific name will stand in the way of future-compatibility.

Having pointed these things out, I think a lot of these could be resolved by reorganizing the code, so adding up the plusses and minuses does not give my total opinion.

Data-structure/namespace

In the GraphQL example the editor is used as top-level selector.
In the selectors example there is a core/editor namespace.

I understand these are just concepts, but I wanted to note that these are not consistent.

Globally defined core data retrieval

Do I understand correctly that the GraphQL implementation allows to define the default post data retrieval functions can be implemented in core itself?

It seems that only the plugin specific data exposing would have to implement specific retrieval separately to be used.

I think it would be nice to have the data "magically" provided for core data, if the data structure has been documented in depth somewhere.
This will allow us a lot of freedom to change the implementation under the hood in the future.

@youknowriad
Copy link
Contributor Author

youknowriad commented Dec 21, 2017

Thanks for these thoughts 👍, like you said, most of the - could be "fixed".

I think it would be nice to have the data "magically" provided for core data, if the data structure has been documented in depth somewhere.
This will allow us a lot of freedom to change the implementation under the hood in the future.

Yes, I thought about this, building "data-only" modules in Core, for example a @wordpress/media module don't do nothing aside registering a media reducer and exposing data. I think this is achievable regardless of the option we choose.

In the GraphQL implementation: This means triggering actions in resolvers if the data is not available yet.
In the Selectors implementation: This means these selectors become something else: selectors + triggering actions. It would be quite similar to the GraphQL implementation but we wouldn't register regular Redux selectors anymore.

Edit

  • It may also make sense to define these "Core Data" selectors/resolvers in the data module itself.

@herregroen
Copy link

herregroen commented Dec 22, 2017

While my general preference goes to the GraphQL proposal, I would like to suggest one improvement to this PR.

Why not use plain old javascript for these selectors? Replacing query with something like the following ( read as pseudo-code, may need some changes :P ):

export const query = ( mapPropsToSelectors ) => ( WrappedComponent ) => {
	return connect( ( state ) => {
		const data = {};

		forOwn( selectors, ( functions, key ) => {
			const wrappedObject = {};

			// Wrap each selector to automatically pass the required state as first argument.
			forOwn( functions, ( selector, selectorKey ) => {
				wrappedObject[ selectorKey ] = ( ...args ) => selector( getState()[ key ], ...args );
			} );

			// Expand the keys by splitting on `/` and `.`.
			const keys = key.split( /\.\// );
			// Assign our wrapped function to a nested object with the correct keys.
			// `core/editor` => { getEditorPostTitle: fn }
			// will become { core: { editor: { getEditorPostTitle: fn } } }
			const obj = keys.reduceRight( ( previousObject, currentKey ) => {
				const currentObject = {};
				currentObject[ currentKey ] = previousObject;
				return currentObject;
			}, wrappedObject );
			// Merge our nested object with the data object.
			merge( data, obj );
		} );

		// Return the data object that can be called with plain javascript.
		return mapPropsToSelectors( data );
	} )( WrappedComponent );
}

Would enable this to be used like this in a wrapped component, which I feel is a much more natural way of calling functions that's more accessible to inexperienced developers. As an added benefit this would allow calling console.log on the data object to easily discover all available data.

import { query } from '@wordpress/data';
const MyComponentWithData = query( ( data ) => {
	return {
		title: data.core.editor.getEditedPostTitle(),
	};
} )( props =>
  <div>{ props.title || 'no title' }</div>
);

@youknowriad
Copy link
Contributor Author

@herregroen Thanks for the proposal, while I think it's probably good to avoid using a "string" to call the selectors, I don't think we should try to map the namespace to an attribute. I'd personally prefer something closer to the API proposed here #4105 (comment)

maybe mix it with the data arg proposal data( 'core/editor' ).getEditedPostTitle().

data/README.md Outdated


### `wp.data.registerSelectors( key: string, selectors: object )`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we put reducerKey here to align with the function definition?

data/index.js Outdated
*
* @param {string} reducerKey Part of the state shape to register the
* selectors for.
* @param {Object} registeredSelectors Selectors to register. Keys will be used
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In docs we have selectors provided as the 2nd param, maybe we should use the same name here, what do you think?

Copy link
Member

@gziolo gziolo Jan 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey, Eslint shadowing again. Maybe newSelectors then :)

data/README.md Outdated
title: select( 'myPlugin', 'getTitle' ),
};
} )( ( { title } ) => <div>{ title }</div> );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest making it more focused on the query HOC by moving ( { title } ) => <div>{ title }</div> to its own variable like this:

const Component = ( { title } ) => <div>{ title }</div>;

wp.data.query( select => {
 	return {
 		title: select( 'myPlugin', 'getTitle' ),
 	};
 } )( Component  );

@gziolo
Copy link
Member

gziolo commented Jan 15, 2018

It looks really solid. I'm more than happy to move forward with it.

About the selectors discovery, I don't think making them accessible like this wp.data.selectors[ 'core/editor' ].getTitle() is a good option because we can't use Proxies yet :( and if we do want something to discover selectors, I think it should a more targed API wp.data.getSelectors( 'core/editor' )

We could discuss the different ways of exposing selectors for long, but we need to start using it first to see how it plays with the real code. I think the current proposal has a very straightforward implementation and a very performant one because it create only one function whenever the state changes.

@gziolo
Copy link
Member

gziolo commented Jan 15, 2018

I added a change to the test file which makes sure that ownProps is properly consumed in query HOC. I think it is ready to go. I recommend having more eyes on this PR before proceeding including @atimmer or @omarreiss :)

@gziolo gziolo force-pushed the try/data-module-expose-with-selectors branch 2 times, most recently from 6cf0741 to 9f6b6e4 Compare January 15, 2018 10:40
Copy link
Member

@atimmer atimmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, let's get it in and iterate further.

data/index.js Outdated
@@ -19,15 +21,15 @@ const store = createStore( initialReducer, {}, flowRight( enhancers ) );
/**
* Registers a new sub reducer to the global state and returns a Redux-like store object.
*
* @param {String} key Reducer key
* @param {Object} reducer Reducer function
* @param {string} reduerKey Reducer key.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A typo in reduerKey.

@jaswrks
Copy link
Contributor

jaswrks commented Jan 15, 2018

Woohoo! Nice work. Love this API ❤️

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would proxying be the only approach to invoke the selectors as a function, if we could assume that connect mapping functions are only called after a selector has already been registered (i.e. the registration could ensure these functions are included in an object passed to the mapping function)?

Generally this looks quite fine to me. I see pros and cons to this vs. the subtly different variations (per-reducer-key query).

One other variation I pondered which doesn't seem to have been proposed yet:

// Simple case: Select from single reducer key
query( 'core/foo', ( select ) => ( {
	/* ... */
} ) )

// Select from multiple reducer keys
query( {
	'core/foo': ( select ) => ( {
		/* ... */
	} ),
	'core/bar': ( select ) => ( {
		/* ... */
	} ),
} );

data/README.md Outdated
### `wp.data.registerSelectors( reducerKey: string, newSelectors: object )`

If your module or plugin needs to expose its state to other modules and plugins, you'll have to register state seclectors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "seclectors" -> "selectors"

@gziolo
Copy link
Member

gziolo commented Jan 17, 2018

One other variation I pondered which doesn't seem to have been proposed yet:

// Simple case: Select from single reducer key
query( 'core/foo', ( select ) => ( {
	/* ... */
} ) )

// Select from multiple reducer keys
query( {
	'core/foo': ( select ) => ( {
		/* ... */
	} ),
	'core/bar': ( select ) => ( {
		/* ... */
	} ),
} );

I proposed to have the grouping, you mentioned, around the key reducer in one of my previous comments, and this makes it usable :)

I also figured out it is also possible to do the following with what we have coded:

query( ( select ) => {
	const fooSelect = select.bind( null,  'core/foo' );
	const barSelect = select.bind( null,  'core/bar' );
	return {
		foo: fooSelect( 'getFoo' ),
		bar: barSelect( 'getBar' ),
	};
} );

@youknowriad
Copy link
Contributor Author

All these alternatives are valid. I personally don't have a strong preference for one over another. I'll just move forward. Better to try in real life and iterate.

@youknowriad youknowriad force-pushed the try/data-module-expose-with-selectors branch from 7008b4e to 67d67b7 Compare January 17, 2018 10:35
@youknowriad
Copy link
Contributor Author

Run the tests locally, merging.

@youknowriad youknowriad merged commit add336f into master Jan 17, 2018
@youknowriad youknowriad deleted the try/data-module-expose-with-selectors branch January 17, 2018 11:23
schlessera added a commit that referenced this pull request Jan 23, 2018
Squashed commit of the following:

commit 4e0358e
Merge: 5f6e8c6 73612cb
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 23 11:19:02 2018 +0100

    Merge pull request #4631 from WordPress/try/new-mover-icons

    Try smaller up/down arrows, and focus management

commit 73612cb
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 23 10:28:59 2018 +0100

    Adjust test to not look for the icon

    The icon is now an SVG passed on

commit 5f6e8c6
Author: Herb Miller <[email protected]>
Date:   Tue Jan 23 04:06:21 2018 +0000

    Fixes #4541 (#1) (#4542)

    * Fixes #4541 (#1)

    * Update ISSUE_TEMPLATE.md

commit 25d90ca
Author: Stephen Edgar <[email protected]>
Date:   Mon Jan 22 11:26:46 2018 +1100

    Scrips: Update verbiage and comments in `install-node-nvm.sh` script (#4624)

commit 456f28a
Author: Andrew Duthie <[email protected]>
Date:   Sat Jan 20 17:13:37 2018 -0500

    Components: Ensure isLoading set to false after request error (#4525)

commit 5760b63
Author: Ramon <[email protected]>
Date:   Sat Jan 20 19:33:25 2018 -0200

    Update "Edit Link" to "Insert/edit link" (#4471)

commit d967017
Merge: 62a9e7b 9da45da
Author: Miguel Fonseca <[email protected]>
Date:   Fri Jan 19 18:36:35 2018 +0000

    Merge pull request #4349 from WordPress/fix/3839-undelayed-slot-prop-update

    fix/3839: Move slot.forceUpdate() to fill's render to fix prop propagation

commit 9da45da
Author: James Johnson <[email protected]>
Date:   Mon Jan 8 16:40:09 2018 +1000

    Move slot.forceUpdate() call into componentWillUpdate

    - Fixes prop propagation across Slot boundary.

commit 62a9e7b
Author: Andrew Duthie <[email protected]>
Date:   Fri Jan 19 12:27:40 2018 -0500

    Block List: Select block only if not already selected (#4586)

commit 8d57578
Author: Andrew Duthie <[email protected]>
Date:   Fri Jan 19 12:24:29 2018 -0500

    Block List: Start multi-selection tracking on mousemove (#4585)

    * Block List: Start multi-selection tracking on mousemove

    * State: Abort state update if multi-select action has no effect

commit d591e58
Author: Ella Van Dorpe <[email protected]>
Date:   Fri Jan 19 18:00:06 2018 +0100

    Add subhead block (#2091)

commit 3568fc4
Author: Jorge <[email protected]>
Date:   Fri Jan 19 16:37:09 2018 +0000

    Added text align feature to cover image. (#4066)

commit 6dd01de
Author: Riad Benguella <[email protected]>
Date:   Fri Jan 19 14:41:36 2018 +0100

    MetaBoxes: Remove dirty-checking metaboxes state (#4184)

    * MetaBoxes: Remove dirty-checking metaboxes state
    * MetaBoxes: compare meta boxes HTML while leaving the editor to warn about unsaved changes
    * Meta Boxes: Changing the way we save metaboxes
    Hidden metaboxes (side) were not saved before

commit 036f60a
Author: Riad Benguella <[email protected]>
Date:   Fri Jan 19 14:34:17 2018 +0100

    Blocks: Showing a preview of the block immediately after drag and drop (#4567)

commit 060200c
Merge: df24fd0 0e6fb4b
Author: Miguel Fonseca <[email protected]>
Date:   Fri Jan 19 11:35:24 2018 +0000

    Merge pull request #4549 from WordPress/add/copy-content-as-extension

    Refactor CopyContentButton as core extension

commit df24fd0
Author: Ella Van Dorpe <[email protected]>
Date:   Fri Jan 19 11:57:40 2018 +0100

    Add HTML handler to dropzone (#4577)

    * Add HTML handler to dropzone

    * Add HTML handler to image placeholder

    * Merge ifs

commit 993561d
Author: mac <[email protected]>
Date:   Thu Jan 18 09:29:19 2018 -0700

    Image Block Link Label Copy Change

commit 5ab37b7
Author: Ella Van Dorpe <[email protected]>
Date:   Fri Jan 19 11:12:51 2018 +0100

    Remove "Open in new window" link option (#4583)

    Reverts #2628.

commit 6ed1573
Author: Grzegorz (Greg) Ziółkowski <[email protected]>
Date:   Fri Jan 19 09:49:04 2018 +0100

    Docs: Update title for the scaffolding blocks document (#4596)

commit 91cb16c
Author: Joen Asmussen <[email protected]>
Date:   Fri Jan 19 09:47:32 2018 +0100

    Try new icons for movers

    These icons are smaller and less obtrusive, which makes them less heavy to look at.

    This PR also employs a workaround to achieve the effect that `:focusring` would, were it implemented (see https://www.youtube.com/watch?v=ilj2P5-5CjI). This is applied only to the mover icons.

    GIF: https://cldup.com/5lyhf0iSTp.gif

commit f43140e
Author: Riad Benguella <[email protected]>
Date:   Fri Jan 19 09:44:04 2018 +0100

    Block versioning: Introduce a migration function (#3673)

commit aa5e157
Author: Jason Caldwell <[email protected]>
Date:   Mon Jan 15 03:28:47 2018 -0900

    Improve `useOnce` documentation.

    #3695

commit 85be4c7
Author: Gary Pendergast <[email protected]>
Date:   Fri Jan 19 14:40:26 2018 +1100

    Use docker-compose for all Docker commands (#4592)

commit a2d64e1
Author: Andrew Duthie <[email protected]>
Date:   Thu Jan 18 12:52:56 2018 -0500

    Block: Move drag handling to instance-bound handler (#4582)

commit 0e6fb4b
Author: Miguel Fonseca <[email protected]>
Date:   Wed Jan 17 15:18:28 2018 +0000

    Refactor CopyContentButton as core extension

    * Use withState & compose, drop class component

    * Cache CopyContentButton element for EditorActions filter

commit 6c256dd
Author: Jorge <[email protected]>
Date:   Tue Jan 16 21:00:01 2018 +0000

    Don't persist mobile and publish sidebar to localStorage.

    Mobile and publish sidebars should when page reloads, even if they were open before.

commit 4d6af27
Author: Jorge <[email protected]>
Date:   Tue Jan 16 20:58:46 2018 +0000

    Implemented mechanism to allow reducers to customise what information gets serialised to localStorage; Changed mechanism to load defaults in loadAndPersist.

commit 1fa9344
Author: Jorge <[email protected]>
Date:   Tue Jan 16 20:43:27 2018 +0000

    Removed old mechanism to avoid mobile sidebar persistence.

    With the last code changes this mechanism is not being used anymore.

commit e24460c
Author: Grzegorz (Greg) Ziółkowski <[email protected]>
Date:   Thu Jan 18 12:37:14 2018 +0100

    Docs: Add page explaining how to scaffold blocks (#4404)

commit b866d21
Merge: 57280d0 d04b78d
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 12:01:35 2018 +0100

    Merge pull request #3996 from WordPress/try/gallery-markup-tweaks

    Try new gallery markup

commit 57280d0
Merge: e97b65f eb954da
Author: Stephen Edgar <[email protected]>
Date:   Thu Jan 18 21:41:59 2018 +1100

    Merge pull request #4563 from WordPress/update/eslint-jsdoc

    JSDoc fixes

commit d04b78d
Author: Riad Benguella <[email protected]>
Date:   Thu Jan 18 11:38:04 2018 +0100

    Gallery Block: Fix tests

commit 91b2504
Author: Riad Benguella <[email protected]>
Date:   Thu Jan 18 11:26:34 2018 +0100

    Gallery Block: Fix deprecated version

commit 450f716
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 11:15:01 2018 +0100

    Try adjusting deprecated attributes

    Also re-add the deprecated CSS class.

commit e97b65f
Merge: f9486f1 5d50586
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 11:13:11 2018 +0100

    Merge pull request #4512 from WordPress/try/new-focus-outlines

    Try new button outline & focus styles

commit 5d50586
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 10:59:27 2018 +0100

    Tweak styles further from revert.

commit eb954da
Merge: 968e87f 48780ab
Author: Stephen Edgar <[email protected]>
Date:   Thu Jan 18 20:55:46 2018 +1100

    Merge branch 'update/eslint-jsdoc' of github.com:WordPress/gutenberg into update/eslint-jsdoc

commit 968e87f
Author: Stephen Edgar <[email protected]>
Date:   Thu Jan 18 20:54:39 2018 +1100

    More JSDoc fixes

commit 1cea78d
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 10:53:27 2018 +0100

    Revert tabindex fix, and reverse active & hover states.

commit 48780ab
Merge: 596ff36 f9486f1
Author: Stephen Edgar <[email protected]>
Date:   Thu Jan 18 20:24:59 2018 +1100

    Merge branch 'master' into update/eslint-jsdoc

commit 3da0798
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 09:49:39 2018 +0100

    Replace all instances of blocks-gallery-image

commit 4466445
Author: Joen Asmussen <[email protected]>
Date:   Thu Jan 18 09:29:05 2018 +0100

    Address feedback

    - Move li outside of component
    - Fix CSS typo
    - Add deprecated section

commit d8eaefb
Author: Joen Asmussen <[email protected]>
Date:   Thu Dec 14 09:56:47 2017 +0100

    Try new gallery markup

    This is a new version of the PR by #3441 by @samikeijonen. It's just basically "rebased".

    It seems to be working fine in practice, the chief purpose is to make the gallery be list based.

    I'm getting "modified externally" warnings, though.

commit f9486f1
Author: Stephen Edgar <[email protected]>
Date:   Thu Jan 18 19:23:33 2018 +1100

    chore: remove `eslines` (#4565)

    * chore: remove `eslines`

    * chore: remove `eslines` from `eslint` npm script

    * chore: remove JSON formatter from `eslint` npm script

commit e9f38ae
Author: Grzegorz (Greg) Ziółkowski <[email protected]>
Date:   Thu Jan 18 09:12:51 2018 +0100

    Components: Force update when new filter added or removed when using withFilters HOC (#4428)

commit cda269d
Author: jaswrks <[email protected]>
Date:   Wed Jan 17 22:48:30 2018 -0900

    Remove danger warning from plugin header (#4552)

    see: #4185

commit 596ff36
Author: Stephen Edgar <[email protected]>
Date:   Thu Jan 18 18:46:05 2018 +1100

    JSDoc fixes

commit e826be5
Author: Lara Schenck <[email protected]>
Date:   Wed Jan 17 23:33:35 2018 -0800

    Add more context to Templates sample code (#4557)

    * Add function and add_action call to sample code

    * Better function name

commit b8566d7
Merge: 64b6017 c442f0e
Author: Robert Anderson <[email protected]>
Date:   Thu Jan 18 09:52:08 2018 +1100

    Merge pull request #4497 from WordPress/update/move-logic-out-of-inserter

    Move data logic out of the inserter

commit c442f0e
Author: Robert Anderson <[email protected]>
Date:   Wed Jan 17 16:33:23 2018 +1100

    Add a unique id to inserter items

    This lets the inserter do faster string comparison between inserter
    items rather than deep object comparison.

commit 6759f55
Author: Robert Anderson <[email protected]>
Date:   Tue Jan 16 13:00:54 2018 +1100

    Move data logic out of the inserter

    Moves the logic that determines which items should appear in the
    inserter into dedicated selector functions. This way, the logic is
    easier to test and can be re-used.

commit 64b6017
Author: Ella Van Dorpe <[email protected]>
Date:   Wed Jan 17 17:18:25 2018 +0100

    Ensure editor still exists after timeout (#4524)

    * Ensure editor still exists after timeout

    * Add doc for setSafeTimeout

commit 0940478
Author: Ella Van Dorpe <[email protected]>
Date:   Wed Jan 17 15:24:32 2018 +0100

    Allow copying text in block (non input) (#4531)

commit 79e9552
Merge: add336f d129a6c
Author: Joen Asmussen <[email protected]>
Date:   Wed Jan 17 12:51:28 2018 +0100

    Merge pull request #4313 from WordPress/fix/blinking-focus-outline

    Fix issue where black rectangle would briefly blink on new paragraphs

commit add336f
Author: Riad Benguella <[email protected]>
Date:   Wed Jan 17 12:23:31 2018 +0100

    Data Module: Expose state using selectors (#4105)

commit 47c36a5
Author: Riad Benguella <[email protected]>
Date:   Fri Jan 12 14:41:18 2018 +0100

    Meta Boxes: Allow collapsing/sorting the meta boxes panels

commit 8d3a673
Author: Josh Pollock <[email protected]>
Date:   Sat Jan 13 15:30:08 2018 -0500

    Add links to specific sections of Redux docs

    #4452

commit 6e2e944
Author: Robert Anderson <[email protected]>
Date:   Wed Jan 17 18:28:48 2018 +1100

    Only minimize -rtl files in production (#4536)

    This improves incremental developmnet build performance by about 3.5x!

commit 9d28bac
Merge: acd3d22 d216fe1
Author: Robert Anderson <[email protected]>
Date:   Wed Jan 17 16:59:04 2018 +1100

    Merge pull request #4538 from WordPress/fix/snapshot-tests

    Fix snapshot tests

commit d216fe1
Author: Robert Anderson <[email protected]>
Date:   Wed Jan 17 16:51:01 2018 +1100

    Fix snapshot tests

commit acd3d22
Author: Walter Ebert <[email protected]>
Date:   Wed Jan 17 04:24:52 2018 +0100

    Remove Vine embed (#4521)

    Vine is no longer a supported oembed provider since WordPress 4.9.0, it can be removed from Gutenberg to match.

commit c433d76
Author: Gary Pendergast <[email protected]>
Date:   Wed Jan 17 13:54:24 2018 +1100

    Improve the build scripts (#4465)

    There's a bunch of stuff that can be automated when setting up a local development environment. Here's some polish, etc.

    Notable changes:

    - Automatically check for and install NVM, update to the correct version of Node.
    - Add some extra information to Docker checks.
    - Add a check and fix for npm/npm#16938, which is super annoying.
    - Switch to using Docker for Composer scripts.
    - Defining the WordPress URL port in docker-compose.yml now defines it everywhere, including Cypress e2e tests.
    - Generally clean up and hide the spammy status messages that don't benefit anyone.
    - Add a welcome message at the end of the setup process.

commit 7f7b607
Author: Helen Hou-Sandi <[email protected]>
Date:   Tue Jan 16 17:44:57 2018 -0500

    Insert `@username` for user mention autocomplete (#4444)

    Rather than inserting a static link and the display name, both of which may change over time and lead to stale content, follow the pattern of existing user mentions in WordPress projects and insert a plaintext mention using the username.

commit 2e276ad
Author: Thorsten Frommen <[email protected]>
Date:   Tue Jan 16 22:27:50 2018 +0100

    Simplify control flow. (#4458)

commit 8cad9ae
Author: Thorsten Frommen <[email protected]>
Date:   Tue Jan 16 22:25:59 2018 +0100

    Remove stray word. (#4459)

commit fdd1568
Author: Sören Wrede <[email protected]>
Date:   Tue Jan 16 22:04:58 2018 +0100

    Remove colon from audio and video block placeholder. (#4431)

commit 75d81e9
Author: Andrew Duthie <[email protected]>
Date:   Tue Jan 16 14:53:00 2018 -0500

    Blocks: Reduce sibling inserter initial height (#4384)

commit 3e08d83
Author: Riad Benguella <[email protected]>
Date:   Tue Jan 16 13:35:21 2018 +0100

    Media: Refactor the MediaUploadButton to be agnostic to its rendered UI

commit 8e87182
Author: Jason Caldwell <[email protected]>
Date:   Mon Jan 15 04:32:21 2018 -0900

    fix: `applyOrUnset()` consistency.

    See: #3859

commit 8f0aab9
Author: Riad Benguella <[email protected]>
Date:   Tue Jan 16 14:30:50 2018 +0100

    Documentation: change default post type term

commit b86cbe2
Author: Riad Benguella <[email protected]>
Date:   Tue Jan 16 14:14:44 2018 +0100

    Documentation: Clarifies how to assign a template to a default Post Type

commit 513534d
Author: Sören Wrede <[email protected]>
Date:   Tue Jan 16 14:19:33 2018 +0100

    Update copyright year to 2018 in license.md (#4511)

commit 14f76e5
Author: Jb Audras <[email protected]>
Date:   Tue Jan 16 14:01:42 2018 +0100

    Add missing alt attribute to image (and gallery) blocks when alt return an empty value (#4363)

commit 789f955
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 16 13:10:34 2018 +0100

    Polish focus styles further

commit 6c65025
Merge: 64a4cf7 8a12860
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 16 12:39:20 2018 +0100

    Merge pull request #4508 from WordPress/update/theme-progress-bar

    Update theme progress color bar to match theme

commit 64a4cf7
Author: Stephen Edgar <[email protected]>
Date:   Tue Jan 16 22:36:00 2018 +1100

    Remove ESLint JSDoc checks, for now (#4510)

commit 8a12860
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 16 12:01:15 2018 +0100

    Update theme progress color bar to match theme

    This makes it so the animated updater matches the WordPress admin color scheme.

commit 030dec3
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 16 11:38:58 2018 +0100

    Fix focus issue with SVGs

commit adbdbb7
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 16 11:35:57 2018 +0100

    Try a different approach for styling movers

commit db533fa
Author: Joen Asmussen <[email protected]>
Date:   Tue Jan 16 11:12:39 2018 +0100

    Try new focus styles

commit f4fb4ad
Author: Grzegorz (Greg) Ziółkowski <[email protected]>
Date:   Tue Jan 16 08:59:59 2018 +0100

    Blocks: Add regression check for block edit using snapshot testing (#4399)

commit 34930ca
Merge: af74fa6 35b8e04
Author: Anton Timmermans <[email protected]>
Date:   Tue Jan 16 08:14:03 2018 +0100

    Merge pull request #4493 from WordPress/update/jsdoc-returns-follow-up

    docs: add preceding line break and remove superfluous spacing in JSDoc `@returns` descriptions

commit 35b8e04
Author: Stephen Edgar <[email protected]>
Date:   Tue Jan 16 09:34:20 2018 +1100

    docs: add preceding line break and remove superfluous spacing in JSDoc `@returns` descriptions

commit af74fa6
Merge: 3f54b38 a6b45ad
Author: Robert Anderson <[email protected]>
Date:   Tue Jan 16 09:20:47 2018 +1100

    Merge pull request #4395 from WordPress/fix/trigger-typing-mode-on-enter

    Trigger typing mode when ENTER is pressed

commit 3f54b38
Author: Jorge <[email protected]>
Date:   Mon Jan 15 17:24:48 2018 +0000

    Fixed erros when adding duplicate tags/flat terms. (#4487)

    If we get an error saying we have a duplicate tag/flat term (tag may have been added by other used since last time we fetched), we search the server for the new tag and we add it to our list.

commit 2bdab14
Author: Tammie Lister <[email protected]>
Date:   Mon Jan 15 11:56:20 2018 +0000

    Added in thrijith as contributor

commit 79bb46e
Author: Thrijith Thankachan <[email protected]>
Date:   Mon Jan 15 17:24:31 2018 +0530

    Video Block: Change block description (#4448)

commit ea36aa5
Author: Stephen Edgar <[email protected]>
Date:   Mon Jan 15 19:51:14 2018 +1100

    chore: add `cypress.env.json` to `.gitignore` (#4466)

commit a418f56
Merge: eb468a8 a2e070a
Author: Joen Asmussen <[email protected]>
Date:   Mon Jan 15 09:21:44 2018 +0100

    Merge pull request #4462 from rileybrook/update/conributing.md-workflow

    Update workflow steps in CONTRIBUTING.md documentation

commit eb468a8
Author: Stephen Edgar <[email protected]>
Date:   Mon Jan 15 19:21:07 2018 +1100

    chore: remove unused `react-markdown` npm module (#4461)

commit 1e81e41
Author: Stephen Edgar <[email protected]>
Date:   Mon Jan 15 19:20:37 2018 +1100

    docs: use `@returns` over `@return` JSDoc tag (#4464)

    Fixes per WordPress JavaScript Inline Coding Standards:

    • Use `@returns` over `@return` JSDoc tag fixing ESLint `jsdoc/check-tag-names` "Invalid JSDoc tag" warnings
    • Ensures there is a blank new line before the `@returns` JSDoc tag
    • Ensures the `@returns` JSDoc tag description ends with a period.

    See https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/javascript/

commit a6b45ad
Author: Robert Anderson <[email protected]>
Date:   Fri Jan 12 12:01:43 2018 +1100

    Trigger typing mode when BACKSPACE is pressed

commit 394c89b
Author: Robert Anderson <[email protected]>
Date:   Thu Jan 11 15:50:22 2018 +1100

    Trigger typing mode when ENTER is pressed

    Splitting a block or inserting a new paragraph block by pressing ENTER
    should engage typing mode.

commit a2e070a
Author: mac <[email protected]>
Date:   Sun Jan 14 19:41:18 2018 -0700

    Update workflow steps in contributing.md documentation

commit 38300ff
Merge: 8ee2b1a 5d4e19d
Author: Robert Anderson <[email protected]>
Date:   Mon Jan 15 10:53:43 2018 +1100

    Merge pull request #4304 from WordPress/fix/content-sanitization

    Enable TinyMCE sanitization when setting HTML content

commit 8ee2b1a
Author: Gary Pendergast <[email protected]>
Date:   Mon Jan 15 09:04:18 2018 +1100

    Force wp-api.js (via Backbone settings) to use HTTP/1.0 methods only. (#4396)

commit 9fe1ddc
Author: Gary Pendergast <[email protected]>
Date:   Mon Jan 15 09:00:10 2018 +1100

    Build Tools: Add support for docker-compose.override.yml (#4457)

    As we don't actually use the `docker` directory to contain anything, the `docker-compose.yml` file has also been moved to the root directory. This tidies up a bunch of commands that used to have to refer to the special file location.

commit ae9b07f
Author: iseulde <[email protected]>
Date:   Fri Jan 12 17:16:05 2018 +0100

    Remove BR logic from list block

commit 8ac6cc8
Author: Riley Brook <[email protected]>
Date:   Fri Jan 12 09:37:26 2018 -0700

    Size to Level (#4440)

    Changes copy from "Size" to Level" displayed within Heading block settings.

commit 440d278
Merge: 66303b3 f0b7447
Author: Miguel Fonseca <[email protected]>
Date:   Fri Jan 12 13:32:04 2018 +0100

    Merge pull request #4429 from WordPress/fix/gutenberg-activation-undefined-constant-warning

    Fix warning plugin activation

commit f0b7447
Author: Miguel Fonseca <[email protected]>
Date:   Fri Jan 12 13:27:14 2018 +0100

    Fix warning plugin activation

    Guard against undefined constant GUTENBERG_DEVELOPMENT_MODE.

commit 66303b3
Author: Ella Van Dorpe <[email protected]>
Date:   Fri Jan 12 13:12:39 2018 +0100

    Image: set width if aligned but unresized (#4356)

commit cd7aa52
Author: Robert Anderson <[email protected]>
Date:   Fri Jan 12 23:09:18 2018 +1100

    Fix the Custom Color button from appearing flat (#4392)

    This is a regression caused by #3958.

commit 4d1ad21
Author: Matias Ventura <[email protected]>
Date:   Fri Jan 12 12:47:03 2018 +0100

    Increase version to 2.0.0. (#4424)

commit e495f6e
Merge: d937d3a e81ab0a
Author: Miguel Fonseca <[email protected]>
Date:   Fri Jan 12 12:16:25 2018 +0100

    Merge pull request #4323 from WordPress/update/copy-from-ellipsis

    Ellipsis: Add button to copy entire document

commit d937d3a
Author: Riad Benguella <[email protected]>
Date:   Thu Jan 11 15:44:41 2018 +0100

    Blocks: Style the "footer" in quotes to ensure backwards compatibility

commit e81ab0a
Author: Miguel Fonseca <[email protected]>
Date:   Thu Jan 4 19:58:52 2018 +0000

    Ellipsis: Add button to copy entire document

    * Scrap `copyAll` shenanigan, use ClipboardButton

    * ClipboardButton: Accept additional onFinishCopy callback

    * Add component EditorActions below ModeSwitcher

    * Don't close menu on copy, show "Copied!" instead

    * MenuItems: Make it more reusable

    * Allow passing extra `classNames` to MenuItemsGroup, don't require a
    `label`

    * Change classes in MenuItemsToggle from `components-menu-items__toggle`
    to `components-menu-items__button is-toggle`

    * EllipsisMenu: Adopt areas Editor, Settings, Tools

commit 27e6fa8
Author: Stephen Edgar <[email protected]>
Date:   Fri Jan 12 18:43:28 2018 +1100

    Use tabs for indentation in build tools JSON files per WP Coding Standards (#4419)

    * chore: Update `.editorconfig` to match WordPress' upstream

    * chore: Use tabs for indentation in `package.json` and `package-lock.json` files

    * chore: Use tabs for indentation in `.eslines.json` file

    * chore: Use tabs for indentation in `composer.lock` file

commit 9212841
Author: Grzegorz (Greg) Ziółkowski <[email protected]>
Date:   Fri Jan 12 08:18:57 2018 +0100

    Docs: Update info about test fixtures (#4401)

commit d129a6c
Author: Joen Asmussen <[email protected]>
Date:   Fri Jan 5 11:21:41 2018 +0100

    Fix issue where black rectangle would briefly blink on new paragraphs

    In master, if you press enter a lot and type a lot, a black rectangle sometimes briefly appears. This is the isEditing rectangle we use to indicate where the cursor is, if it's not in text, i.e. if you have a placeholder selected.

    This PR adds a teensy delay to this so it shouldn't show up.

commit 5d4e19d
Author: Robert Anderson <[email protected]>
Date:   Fri Jan 5 11:01:29 2018 +1100

    Enable TinyMCE sanitization when setting HTML content

    We were previously disabling TinyMCE sanitization by calling setContent
    with `{ format: 'raw' }`. Doing so, however, causes issues when
    setContent is called with prettified HTML, e.g. when a list block is
    updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A way for plugin developers to access the editor state?
10 participants