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

Create an API for defining blocks in the editor. #104

Closed
BE-Webdesign opened this issue Feb 20, 2017 · 34 comments
Closed

Create an API for defining blocks in the editor. #104

BE-Webdesign opened this issue Feb 20, 2017 · 34 comments
Labels
[Type] Task Issues or PRs that have been broken down into an individual action to take [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible
Projects

Comments

@BE-Webdesign
Copy link
Contributor

This can serve as a discussion for creating an API for the editor. Share your thoughts 😄

@BE-Webdesign
Copy link
Contributor Author

BE-Webdesign commented Feb 20, 2017

Here are things I think the API should do/have:

  • Be extensible
  • Be easy to use
  • Code should be easy to read and understand.
  • Have great documentation/tutorials
  • Provide a way to register types of blocks
  • Create a separation between the blocks and their actual presentation. ( Blocks should be plain ole JavaScript objects that could then render themselves into what is needed. Most likely TinyMCE and DOM nodes. )

Addendum ( Block Types should most likely be registered server side and exposed to the client. )

@mtias mtias added the [Type] Task Issues or PRs that have been broken down into an individual action to take label Feb 20, 2017
@mtias mtias changed the title Create an API for the editor. Feb 20, 2017
@mtias mtias added this to Technical in Prototypes Feb 20, 2017
@aduth
Copy link
Member

aduth commented Feb 20, 2017

Related controls discussion: #16

Taking a few of the current mockups as a basis, I've identified some/all of the pieces a developer should expect to be able to implement:

  • Label
    • To be shown in insertion dialog
  • Icon
  • Block controls
  • Inline controls (optional)
    • In the case of the quote mockup, one should expect to be able to format text. Is this merely supporting nested plain text block?
    • It's possible that some blocks may want to support only a subset of formatting options
  • Children
    • Given sub-note of inline controls, perhaps blocks could allow nested block descendants
    • Future support of a "Columns" block?
  • Custom editor-specific form
    • In the case of the quote mockup, the quote and citation may be separate fields
  • Transform support
    • Mockup
    • e.g. change plain text to heading or quote
  • Advanced settings popover ("Inspector")

Below are a few of my early prototypes which include rough implementations of some or all of these requirements:

Given discussion at aduth/wp-block#1, I've also been wondering if we could optionally / alternatively support server-side block registration options, with the following goals in mind:

  • Sanitize block attribute values based on defined types
  • Scaffold UIs based on defined block attribute types
    • These would admittedly not be as great a user experience, but seems to be an easy way for developers to make quick early iterations of a block, or for freelancers/agencies who can't necessarily justify creating extremely polished block UIs
  • Allow blocks to be exposed through REST API or elsewhere in PHP, as current proposals expect registration to occur within browser client

We could look to Shortcake and JS Widgets for inspiration on implementing / consolidating server-side registration if it's a path we want to pursue (cc @westonruter @mattheu @danielbachhuber )

Less obvious, but if we decide to add a new syntax for blocks, we'll also want to consider how to add backwards compatibility support for e.g. captioned images (currently shortcode) which should either be supported by or transparently upgraded to the new recommended block. This might need to be a separate issue.

@aduth
Copy link
Member

aduth commented Feb 20, 2017

Getting into a little more detail, for both block and inline controls, we'll have the following requirements (some assuming we follow proposed block comment syntax):

  • Label
    • Used as tooltip / title
  • Icon
    • Simplest would be a string reference to icon name of either the Dashicon or Gridicon (whatever we settle on)
    • Optionally supporting image URL, similar to register_post_type's menu_icon
    • Perhaps too complex for the sake of optimization, but in my latest prototype I'd made this a reference to a virtual DOM component primarily to avoid over-including unused icons
  • Is selected?
    • Could either be associated with some attribute of a block, or simply passed a function and expected to return a truthy value (arguments include block attributes, children, ...)
  • Click/tap behavior
    • For inline controls, it's likely we'd need to execute some command on the TinyMCE instance (regardless of whether we take approach of single or multiple instances)
    • For block level controls, this may either change content of the block or affect its attributes
@westonruter
Copy link
Member

We could look to Shortcake and JS Widgets for inspiration on implementing / consolidating server-side registration if it's a path we want to pursue

Just to note here that JS Widgets 0.4 was recently released and it includes full integration with Shortcake so that all widgets defined as “JS widgets” are automatically also available as Shortcake post elements (content blocks). Likewise it introduces icons for widgets (current Dashicons).

The server-side registration ensures that that the widgets (blocks) can be exposed in the REST API and that the widget instance data is guaranteed to be JSON-representable so that the data can be manipulated directly with JS (see WP-CORE#35574, WP-CORE#33507). The widget also then defines the interface for manipulating the data, sanitizing the data, and rendering the data with PHP. The shortcode on the other hand only addresses the last piece, the rendering of the data. The Shortcake plugin was developed to implement the shortcode UI which essentially is a JS-driven version of what widgets historically handled with PHP (WP_Widget::form() and WP_Widget::update()), and thus JS Widgets is able to provide the plumbing for how Shortcake manages a widget shortcode's state.

@jasmussen
Copy link
Contributor

jasmussen commented Feb 21, 2017

In the case of the quote mockup, one should expect to be able to format text. Is this merely supporting nested plain text block?

We should probably not tackle nested blocks for the editor focus. This will absolutely become necessary for the customization focus, but probably best as something to keep in mind but not work on.

Incidentally you pointed out an error in the mockups. Yes, you should be able to format quotes. The omission of controls was in error. Here's an updated mockup:

quote 2

It's possible that some blocks may want to support only a subset of formatting options

Absolutely. Headings probably shouldn't have any formatting at all. I'm sure there will be other blocks with unique requirements.

@Lewiscowles1986
Copy link
Contributor

Lewiscowles1986 commented Mar 1, 2017

Are there plans for what to do with oEmbed content like if someone posts a link to a YT in a paragraph?

I'd think it's safer to

  • simply split the paragraph into two paragraphs with an oEmbed in-between if oEmbed link not at start or very end of content
  • simply end the paragraph before the oEmbed if there is no text after the oEmbed link
  • prepend the oEmbed if it's at the start of a paragraph
@jasmussen
Copy link
Contributor

jasmussen commented Mar 1, 2017

Are there plans for what to do with oEmbed content like if someone posts a link to a YT in a paragraph?

Some discussion here: #81 (comment)

See also #24 (comment)

@aduth
Copy link
Member

aduth commented Mar 1, 2017

Are there plans for what to do with oEmbed content like if someone posts a link to a YT in a paragraph?

I was going to mention that in complementing discussion in #81, it would be nice to support blocks registering as being associated with a particular oEmbed URL pattern, such as to allow a YouTube block to enable the user to configure features like start time and autoplay. However, in looking at a few examples, it's not commonly supported to customize the embedded URL to affect these changes. In YouTube's case, you'd have to modify the markup of the embedded frame returned, or for Vimeo passing as arguments to the oEmbed request itself. Which is to say, neither of these services would allow you to control their embed behavior by the URL we'd expect to be saved in post content.

@mtias mtias added the [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible label Mar 7, 2017
@aduth
Copy link
Member

aduth commented Mar 15, 2017

Stepping back for a moment, I thought it could be useful to outline some requirements of a block API for both a block implementer (plugin author) and the editor itself, as well as some ideas I've been exploring as conclusions of these requirements.

Requirements

Plugin Author:

At it's most basic, the idea of a user inserting a block is...

  • Inserting some markup into post content
  • In all but a few cases, the markup will need some customization (think "state" of a block)
  • Some overlap exists, but ideally an editor representation of a block could be distinct from what's shown on the front end of a site (think empty states for an embed, placeholders for cite/caption)

There are a few more nuanced requirements or desires, a few highlighted here:

  • If we need to define complex behaviors for editable fields, it would be good for these to be generalized in such a way for reuse (e.g. allowing only certain inline markup in image caption)
  • I may need to define some default styles for my block's appearance on the front-end in addition to within the editor
  • As a block implementer, I only need to be concerned with the logic of my own block, never with the editor context or sibling blocks

Editor:

Ideally, the editor...

  • Can render a block at any point in time given its known state (for the editor or for post content) without a round-trip to the server
  • Can make available the presence and ideally state and structure of a block from PHP / REST API (so as to enable third party clients including mobile apps to make sense of them)

Conclusions / Ideas:

Block Demarcation Syntax

There have been some explorations of a block demarcation syntax, such as that in the "Coda" section of the original technical overview post. Here it was proposed to use comments to mark the bounds of a block:

<!-- wp:image -->
<figure>
  <img src="/">
  <figcaption>A picture is worth a thousand words</figcaption>
</figure>
<!-- /wp -->

The post grammar explorations took this further to consider encoding some attributes within the comment syntax itself:

<!-- wp:image src:"/" caption:"A picture is worth a thousand words" -->
<figure>
  <img src="/">
  <figcaption>A picture is worth a thousand words</figcaption>
</figure>
<!-- /wp -->

The idea of serializing a block's state entirely within the comment is nice because it can be easily parsed and exposed, even server-side and made available through the REST API. It also enables a block to be more easily rendered because the block's rendering logic becomes a function of its current state (if you're familiar with React paradigms, much like the idea of "components" and "props"). It lessens worries of markup becoming becoming out of sync because we treat the encoded state as the ultimate source of truth, we know what to expect and, if we find that the markup differs, we can provide fallbacks. Finally, it avoids the plugin author needing to manually determine their own block's state by parsing the DOM or traversing an AST.

The most obvious downside is the amount of duplication that occurs between the attributes and the markup itself. I think there are a few options:

  • Bite the bullet and accept the duplication (see also: post revisions)
  • Encode only a few attributes to be used as hints (this sacrifices most of the benefits)
  • Store state elsewhere outside of the markup itself, but keep block demarcators and create a reference of a block's markup to its associated state

To this last point, I think an idea that @danielbachhuber had considered for secret data (aduth/wp-block#2 (comment)) could be useful for all cases. If the state of a block is only truly necessary in its raw form in the context of the editor and from the REST API, it seems reasonable to store this elsewhere as post meta. So the markup becomes:

<!-- wp:image 841 -->
<figure>
  <img src="/">
  <figcaption>A picture is worth a thousand words</figcaption>
</figure>
<!-- /wp -->

Where 841 is a meta_id of wp_postmeta whose meta_value is the serialized form of block state.

Edit: Maybe this becomes simpler if the type itself is moved to post meta, where comments are generalized e.g. <!-- wp:block 228 -->

Block Schemas

While the above syntax can enable us to more easily make the state of a block available to other clients such as mobile apps, it's still not sufficient to enable them to present any sort of editable form. To support this and inspired by previous discussion in aduth/wp-block#1, there may be value in allowing the minimal representation of a block to be defined as a schema server-side.

register_block( 'image', [
	'schema' => [
		'type' => 'object',
		'properties' => [
			'src'     => [ 'type' => 'string' ],
			'caption' => [ 'type' => 'string' ]
		]
	]
] );

The benefits here would be:

  • Consistency with REST API controller schemas
  • Combined with above syntax explorations, enables access to both state and structure of a block outside of the browser context
  • Provides an approachable interface for creating block prototypes, which can be progressively enhanced in the context of the editor, i.e. complementary JavaScript APIs to enhance block editor experience to achieve desired UX

Componentization of Complex Behaviors

While it's yet to be decided how far we take the idea of React's "UI a function of state", it leads naturally to componentizing not only blocks, but common behaviors between blocks. In the current multi-instance prototype, @youknowriad has applied this as far as toolbars being the responsibility of a block to render, which is not as difficult as it seems when masked as a simple ToolbarControls component.

To my own earlier example, if one needed to control complex editable behaviors such as allowable markup, these could act as arguments (props) to a shared editable interface.

Thinking more concretely and permitting the exploration of React's JSX syntax, a blocks editor render logic could amount to roughly:

function ImageBlock( state, onChange ) {
	return (
		<figure>
			<Toolbar />
			<Media
				src={ state.src }
				onChange={ ( src ) => onChange( { src } ) } />
			<Editable
				inline
				allowedTags={ [ 'strong', 'em', 'a' ] }
				value={ state.caption }
				onChange=( ( caption ) => onChange( { caption } ) ) />
		</figure>
	);
}
@youknowriad
Copy link
Contributor

youknowriad commented Mar 15, 2017

Thanks @aduth This is really a great summary of the block API needs.

As a block implementer, I only need to be concerned with the logic of my own block, never with the editor context or sibling blocks

I just have some concerns regarding this. I agree it's ideal if we could limit the block API to the current block itself but I think it's not always possible. How do you think switching block types (we have this on the current prototypes) could work without knowledge about the block types to be switched to/from? Do you imagine a block abstraction like block category or something?

The same concerns could apply while "merging" blocks, merging happens if we hit backspace at the beginning of a block.

@Lewiscowles1986
Copy link
Contributor

@youknowriad AFAIK the oEmbed has similar problems currently. Surely that is something for another issue? Perhaps one referencing this one.

@joyously
Copy link

joyously commented Mar 15, 2017

What happens when the raw editor is used to modify the HTML? In the example of an image that has a postmeta reference containing the src, it will no longer match if I type over the HTML src tag to show a different image. Is there a way to recover from that sort of thing? Or what about typing over the figure tag to make it a paragraph? Or mangling the quotes or brackets?
How will the block editor fail gracefully in these situations?
#testreminder

@ellatrix
Copy link
Member

@youknowriad makes a good point. There needs to be logic somewhere to transform a paragraph (or a collection of paragraphs and lines with line breaks) into a list and back. Atm the single prototype handles this by passing the node, and the block handles the transformation to and from this "base" state.

Similarly a block such as a block quote or a custom section block will need to be able to wrap a (collection of) blocks and unwrap them again.

@aduth
Copy link
Member

aduth commented Mar 16, 2017

I agree it's ideal if we could limit the block API to the current block itself but I think it's not always possible. How do you think switching block types (we have this on the current prototypes) could work without knowledge about the block types to be switched to/from?

@youknowriad This is good to raise, and is indeed an inevitable interaction between blocks. With the ideal in mind, we could at least position this such that a block defines what it can be initialized from (as an explicit opt-in to the behavior) rather than what it can be transformed to.

What happens when the raw editor is used to modify the HTML?

@joyously Yes, this could be a problem if we move state of a block out of the markup, because while we've significantly improved developer experience of block implementer by removing the concern of parsing state, the implications are that edits can only be performed on the state data directly, never on the resulting markup. These scenarios are easy enough to detect, if we find that the markup differs from what we'd expect given the current state. In these cases we may be forced to downgrade to a more generic block, i.e. editing src manually would lose distinction of it being an image block and become something like a "raw HTML" block.

@sirbrillig
Copy link

i.e. editing src manually would lose distinction of it being an image block and become something like a "raw HTML" block.

Another possible UX could be that the block detects that its markup is different from what it would generate and asks the user what to do (it doesn't have to be able to parse the markup, it can just diff it with the current output). Something like, "The HTML of this block has been manually modified. Do you want to convert this into an HTML block or restore the last version of this block before it was modified?"

@jasmussen
Copy link
Contributor

Something like, "The HTML of this block has been manually modified. Do you want to convert this into an HTML block or restore the last version of this block before it was modified?"

This is pretty much exactly what Matt proposed very early on. He called it an I know what I'm doing block:

so we parsed a post, found some sections we know exactly what to do with, and some that we have no idea
[...]
essentially an "I know what I'm doing" block/section 🙂

@westonruter
Copy link
Member

Yes, this could be a problem if we move state of a block out of the markup, because while we've significantly improved developer experience of block implementer by removing the concern of parsing state, the implications are that edits can only be performed on the state data directly, never on the resulting markup.

@aduth another problem with storing the block state in postmeta is that the state is then no longer tracked in post revisions with the content. Maybe this would be solved when revisions support is added for postmeta (#20564), or maybe also there would to be potential for the content and the corresponding postmeta to get out of sync.

@aduth
Copy link
Member

aduth commented Mar 17, 2017

Ah, thanks so much for raising that @westonruter , that's a very good point and could have bitten us hard later down the road 😬 Thanks also for the link to the ticket. Reading through and perusing the latest plugin code, it appears to be a good fit for what we'd need in tracking meta with each revision (cc @adamsilverstein as owner).

At worst and while certainly not ideal, storing state in its serialized form in the comment itself doesn't seem out of the question. Doing so would sacrifice some of the benefits, namely: sending more to the front-end than necessary and losing ability to store secrets.

@azaozz
Copy link
Contributor

azaozz commented Mar 17, 2017

Few problems with this approach:

  1. Removes post_content as "the source of truth". Basically the HTML in post_content becomes non-editable and something like pre-rendered variant of the user input.
  2. Because of the above, the HTML editor becomes useless/pointless. Even a small variation in the HTML (for example adding an attribute to a tag) will invalidate it and make the block non-editable in the "visual" editor. This would be a pretty dismal user experience. Thinking about admins or editors trying to do their job after a contributor or an author creates new post, etc.
  3. Storing the "block state" in post_meta sounds like a good idea. However imagine a post with ~50 blocks (not uncommon) having 20-30 revisions (also not uncommon). To save such post we will need ~1500 rows in the DB! The post_meta table will literally "explode" :)
  4. What would be the "block state" when the user pastes big chunk of HTML, for example: a 500 cell table from Excel? Do we duplicate that whole table and save it separately?

The idea of serializing a block's state entirely within the comment is nice because it can be easily parsed and exposed, even server-side and made available through the REST API. It also enables a block to be more easily rendered because the block's rendering logic becomes a function of its current state...

As far as I see most blocks in a post will be (big) chunks of HTML. They will only have one state (i.e. will be stateless) and have no settings. As HTML they are "ready to go" and will not need parsing or rendering. The "block state" would be useless for them.

On the other hand this is a good idea for "dynamic blocks". In the current editor the "state" of dynamic blocks (a.k.a. wpviews) is the text string used to create them (usually a shortcode or URL). This works pretty well in the HTML editor too as the actual block content is removed when switching to it and replaced with the "block state", then the "block" is rendered again on switching back to visual. Of course this can be extended for use with the block demarcation.

@Lewiscowles1986
Copy link
Contributor

At the point post_content is no longer the universal source of content for core post-types, does it not beg the question, why are we not using a document db, or storing the bulk of the post as a document or with document semantics?

I'm not sure a JSON field in MySQL is such a good option (although it's query-able), but for some systems that live on top of WordPress there are already a litany of fields jammed into the post meta table(s)

@aduth
Copy link
Member

aduth commented Mar 18, 2017

Another problem I think we've overlooked 'til now is that while we've been discussing options for universal understanding between browser and server of block state and state shape, we've not put the same consideration toward generating block markup. So even if the server or mobile app is able to understand and perhaps even update the raw state values, as of now we have no consensus on how to update the markup accordingly.

As an addendum to my earlier comment, it should be a requirement of the editor that a client is able to update its markup in response to user input without a round-trip to the server.

Off the top of my head, we may have a couple options, neither of which I'm particularly happy with:

  • A block's markup rendering is implemented in JavaScript, meaning any client (like the mobile app) must have access to a JavaScript runtime in order to generate the markup (WebView, JavaScriptCore). The server would not be able to generate markup unless Node.js or V8js are detected (we should assume most hosts will not support these).
  • A block's markup rendering is implemented in PHP, but in a template language that can be understood and mimicked in a client. An obvious candidate is sprintf (sprintf.js), which is not a joy to work with for complex markup, might have sanitization implications, and would not provide us with good patterns for sharing common complex behavior among blocks.

Does anyone have ideas for how we might tackle this?

@westonruter
Copy link
Member

In an ideal world, the client and server would be able to render a block. But as you note, this is really only feasible if both the server and the client are running the same language (e.g. JavaScript)… or if there is a sufficiently powerful templating language that has implementations in both JS and PHP, and I don't think Mustache is powerful enough.

I'm inclined think it is not reasonable to expect that the arbitrarily-complex rendering logic on the frontend (in PHP) to be able to be run on the client by JavaScript (in the editor) as well. I think the approach that Shortcake took by rendering shortcodes on the server to be a reasonable baseline pattern to follow with rendering blocks in the editor. Otherwise, a block could provide a basic rough/raw rendering of a block for previewing in the context of the editor, such as is presently done with image galleries.

@sirbrillig
Copy link

sirbrillig commented Mar 20, 2017

I ran into this same challenge when I was exploring these ideas at the end of last year. Mostly I had the same thoughts as you @aduth and @westonruter: shared markup language (that's probably insufficient), or server-rendered only (makes offline impossible, slow to update, and sucks for poor connections). I was only able to come up with two conclusions of my own:

  • It could be possible to write a rendering function in both PHP and JavaScript for each static block. This would be really annoying for a developer, but could possibly work if the tooling/templating was really good.
  • Since the editor is always client-side (JS or native running JS in a web view) we can always generate markup on the client in JS and save it to the server. This is just what you were describing above, but I don't see a big problem with requiring native clients to support JavaScript. I would note, though, that dynamic blocks will likely need to be rendered server-side, so they will need to be written in PHP. I suppose my question is: why does the server need to be able to generate static block markup?
@aduth
Copy link
Member

aduth commented Mar 20, 2017

This is just what you were describing above, but I don't see a big problem with requiring native clients to support JavaScript.

Do you have anything specific in mind for an approach here? I've been thinking about this a bit and was curious if we could either treat the block effectively as an iframe via WebView (with some communication to the parent native context), or generate a scaffolded form from a block's schema and, upon change, execute the JavaScript for generating markup given a particular set of block attributes. This thinking might be a little naive since I've not worked much in a native environment. Those more familiar could indulge us with possible gotchas, particularly around loading scripts from a user's own site.

@BE-Webdesign
Copy link
Contributor Author

To throw in my two cents:

I agree with azaozz's sentiments. To me the editor should only be concerned with manipulating the post_content which is then sent back to the server and saved. The server would send back out the previously saved post_content pretty much like what WordPress already does. The client would parse the post_content into a state tree which can be manipulated and re rendered, or not; as TinyMCE could essentially handle that for us. By keeping the flow the same we most likely will have 100% backwards compatibility with the current WP Editor. The new one will be a lot shinier though and provide a more seamless inline editing experience.

Proposed Flow:

post_content in DB (mostly just HTML) --render-to-editor-> Editor parses post_content into the editable UI (should be handled by TinyMCE) --save-to-server-> The post_content markup is saved in the same fashion WP currently handles everything. The more I think about this project, the more I think the focus in some ways should be centered around making an awesome single TinyMCE instance, that has an inline block editing UI. After looking over some of the things that can be done with TinyMCE, a lot of our problems can be solved by hacking on the APIs it provides.

On the "secret/private" data idea:

This type of data should/would exist only on "dynamic blocks" of content. We should make use of the shortcodes API already present in WordPress to handle that kind of stuff and improve that experience via iseulde's idea. Any reference data that needs to be used would be accessed via the shortcode/resource-id to prevent the sensitive data from being displayed in the actual markup publicly.

Block Registry/Definition API:

The API for defining/registering blocks should be very simple and only be concerned with defining/registering. As blocks are registered there should be someway for TinyMCE to pull data from the registered blocks and add that to the interface for the editor. The registering of blocks could happen server side, and could be pulled into the JS realm when the editor is being initialized. It could also happen client side and forego PHP, however the more I think about it the less I like this approach. There should probably be an association between a block and its controls, so that TinyMCE can dynamically generate the appropriate controls of a selected block based on the block types registered to the editor.

Server vs Client:

I do not see any benefit to trying to have the server render a block via static state, that should be handled via JavaScript. The way in which WordPress interacts with PHP/HTTP is stateless. The initial render and the previously saved output of the editor are one in the same. Adding an extra layer where PHP is rendering static state data as HTML seems like an unnecessary step. Use the server to serve what is already saved and let the client interpret the saved post_content and provide a GUI to manipulate that interpreted state. "Dynamic Blocks" should be rendered via the server in some form or another, (for now shortcodes somewhat work) or at the bare minimum the server should expose what controls/state is necessary to render a dynamic block client side.

Environment:

By contrast, what's the alternative? Offering a node or markup where the developer is expected to attach their event handlers and update the markup in response to the user making changes? This works, but is fragile at best.

This is basically what TinyMCE does and although I agree it is fragile, it is also probably the most practical approach moving forward. I believe digging into the flexibility of TinyMCE to enable it to understand blocks properly is probably more important than worrying about rendering state to markup. A state -> markup system can always be created further down the road if it is ever considered that TinyMCE won't be used anymore.

We also lose the ability to make meaningful observations about a block's markup in anything except the browser (i.e. how does the mobile app know how to do anything with Plugin X's special image block?).

Plugin X's special image block type could be registered to expose data that could be used in a non browser environment. The HTML could be parsed as the state and after it is manipulated then rendered as new HTML in a non browser environment. The exposed block type data could be used in tandem with the HTML in a non browser environment. I think veering away from HTML as the main data format of representing post_content, although technically appealing, would be impractical in the context of WordPress and TinyMCE.

how far we take the idea of React's "UI a function of state"

Make the UI a function of post_content. Essentially a state tree and the post_content are just a different representation of the same thing.

tl;dr:

Don't over complicate things and veer too far away from the flow of data WordPress already uses. I think the Block Type Defining API should be server side in PHP. The work on the editor should mainly be focused on making a Single TinyMCE instance understand how to parse, interpret and modify blocks, which are then saved as post_content in the typical WordPress fashion as a mix of HTML and shortcodesque things.

@aduth
Copy link
Member

aduth commented Mar 22, 2017

@BE-Webdesign Good stuff, I can always get behind efforts to avoid introducing unnecessary complexity.

That said, let's not trivialize making sense of the markup nor working with a DOM. In some ways we've done ourselves a disservice by starting with very simple block types. As far as implementing blocks go, headings and paragraphs are solved problems. The more interesting cases are galleries, contact forms, sliders, maps, repeaters, testimonials, subscribe forms, logo soup, plans comparisons, etc. We should be thinking about all of these block types as we work through the APIs that developers will use to build them.

Editor parses post_content into the editable UI (should be handled by TinyMCE)

This is easy for a single element like a paragraph tag, but TinyMCE won't be able to make sense of more complex markup on its own. The step from post_content to editable UI is a big one, because the markup needs to be transformed from one which is appropriate for published content to a UI which makes the most sense for edits, all the while preserving underlying values back and forth.

TinyMCE can dynamically generate the appropriate controls of a selected block based on the block types registered to the editor

Dynamically generated fields don't make for a good UX. When I'm adding a map block, I should see a map, not just a text input.

[...] the developer is expected to attach their event handlers and update the markup in response to the user making changes [...]

This is basically what TinyMCE does and although I agree it is fragile, it is also probably the most practical approach moving forward

Kindly I disagree. For anything but the simplest elements, working with and keeping the DOM in sync with our understanding of state quickly becomes very difficult. Introducing conventions or tools is perfectly fine if the cost of becoming familiar with them is strongly negated by an increased sense of overall confidence on the developer's part to create sound implementations.


Now a few points to concede on my part:

  • Shortcodes would be a reasonable practical solution to a need for secret data. It's not a great overall solution if we were to ever want to consolidate the idea of a shortcode into a single unified block pattern, and shortcodes seem better suited for dynamic content (in my example, "Gravatar" would be a static block).
  • Maybe keeping state in the DOM is fine, but we still need patterns around making sense of the underlying values. We could do this by mapping data- attributes like @mtias described, assuming the implementation of a parse function, or perhaps another solution that's yet to be explored. Despite all its downsides, the one thing "storing in meta" had going for it was being totally transparent to the block implementer.
  • We have a choice on just how opinionated we want to be with patterns. The block proposal in Editor Blocks API proposal #300 is less opinionated in that by providing access to a raw DOM node to work with in the editor, a developer can choose to use whichever tools they're most comfortable with. By contrast, my own in Add API documentation for blocks and element #302 is admittedly more opinionated with the introduction of React, but argues in doing so that it's the best and most succinct fit for the requirements.
@BE-Webdesign
Copy link
Contributor Author

BE-Webdesign commented Mar 23, 2017

@aduth,

I think for the most part we are on the same page, and I probably am not articulating my ideas too well. My ideas could also be terrible 😄 . I am hoping there can be a way forward that somehow the new block editor can be jump started by post_content that a WordPress install already has, that could include shortcodes. As the block editor is used the block demarcators will be added and store the state into the post_content, so on the next rendering of the editor, the information for the blocks will be there. Getting TinyMCE to do that will certainly be a pain, but I think it could potentially lead to a smooth transition from the current editor to a new block based editor.

The step from post_content to editable UI is a big one, because the markup needs to be transformed from one which is appropriate for published content to a UI which makes the most sense for edits, all the while preserving underlying values back and forth.

Definitely, and this is what TinyMCE kind of does for us or at least closes that gap a bit. I think it is possible to get TinyMCE to understand "blocks" from the post_content and render the appropriate UI based solely off of information stored in post_content.

Dynamically generated fields don't make for a good UX. When I'm adding a map block, I should see a map, not just a text input.

I was talking about the controls for a block, a map will definitely be there for a map block. So for a "map block" TinyMCE will generate a control that can open a modal or something to switch up the map settings. I am probably not explaining my ideas well 😄 .

Kindly I disagree. For anything but the simplest elements, working with and keeping the DOM in sync with our understanding of state quickly becomes very difficult. Introducing conventions or tools is perfectly fine if the cost of becoming familiar with them is strongly negated by an increased sense of overall confidence on the developer's part to create sound implementations.

You could have React components inside the TinyMCE instance ( or whatever you want really ) to ease the handling of a more complex block.

@androb
Copy link
Contributor

androb commented Mar 23, 2017

Re @BE-Webdesign

You could have React components inside the TinyMCE instance ( or whatever you want really ) to ease the handling of a more complex block.

This is exactly what the TinyMCE Core team are looking at the moment. We want to be able to support "blocks", "components", "widgets" or whatever to coexist both "in" TinyMCE as well as outside of it. We are trying to get to some sort of 'best of both worlds' approach... but appreciate this project is moving very fast. We're trying to bring the TinyMCE team's ideas in :)

@ellatrix
Copy link
Member

Experimenting a bit with some of the ideas @aduth had with having a render function and parsing, but without touching the DOM. It would look something like this, where the received content is JSON and h has helpers for this content. Instead of using arrays, you can also use h( name, { ..attrs }, ...children ) and if the developer wants, they can use JSX to generate it. render will need to handle empty props to insert an empty version (placeholder) of the block.

function render( props ) {
	return (
		[ 'figure', { contenteditable: false },
			( ! props.src ?
				[ 'div', { onClick: onClick },
					[ 'svg', ... ],
					[ 'p', 'Pick image' ]
				] :
				[ 'img', { alt: props.alt, src: props.src } ]
			),
			[ 'figcaption', {
				contenteditable: true,
				placeholder: 'Write caption\u2026',
			},
				...props.caption
			]
		]
	);
}

function getProps( content, h ) {
	return {
		alt: h.getAttribute( h.find( content, 'img' ), 'alt' ),
		src: h.getAttribute( h.find( content, 'img' ), 'src' ),
		caption: h.getChildren( h.find( content, 'figcaption' ) )
	};
}

function onClick( props, callback ) {
	filePicker().then( function( files ) {
		...
		callback( render( { src: src } ) );
	} );
}

registerBlock( {
	name: 'image',
	...
	controls: [ ... ],
	render: render,
	getProps: getProps
} );
@aduth aduth mentioned this issue Mar 24, 2017
hypest pushed a commit that referenced this issue Nov 2, 2018
Fix paragraph splits on the Paragraph block
ntwb added a commit that referenced this issue May 31, 2020
gziolo pushed a commit that referenced this issue Dec 18, 2020
* chore(package): update stylelint to version 7.0.0 (#83)

* fix: Deprecated `no-missing-eof-newline` rule. Use the new `no-missing-end-of-source-newline` rule instead. (#84)

* fix: Fixed font-family-name-quotes` test warning message in `values.js`. (#85)

* feat: Add `property-no-unknown` rule. (#86)

* Update install instructions to add `--save-dev`

* chore(package): update stylelint to version 7.2.0 (#87)

* chore(package): update AVA to version 0.16.0 (#88)

* chore(package): update eslint-config-stylelint to version 4.0.0 (#89)

* chore(package): update ESLint to version 3.0.0 (#90)

* feat: Add `at-rule-no-unknown` rule. (#91)

* feat: Add `selector-class-pattern` and `selector-id-pattern` rules. (#92)

* Prepare 9.0.0

* Merge branch 'master' of github.com:ntwb/stylelint-config-wordpress

* feat: Add SCSS preset config (#96)

* feat: Add SCSS preset config

* fix: Include README.md and scss.js in package.json files list

* test: Add initial SCSS tests

* Prepare 9.1.0

* Prepare 9.1.1

* refactor: Use ECMAScript 8/2017, use async/await instead of returning a promise and move css code out of tests to individual files

* feat: Use ECMAScript 8/2017

* refactor: Use async/await instead of returning a promise and move css code out of tests to individual files

* chore(package): update dependencies (#100)

https://greenkeeper.io/

* chore: Add NodeJS 7 to Travis & AppVeyor CI test matrix's (#102)

* chore(package): update stylelint to version 7.5.0 (#103)

* chore: Add NodeJS 7.x changelog note

* feat: Add `selector-no-empty` rule. (#104)

* chore(package): Update `eslint-plugin-ava` to version 4.0.0 (#105)

* fix: SCSS: Dissalow `@debug` at-rules.

* fix: SCSS: Add `scss/selector-no-redundant-nesting-selector` rule.

* Update ava to the latest version 🚀 (#109)

* chore(package): update ava to version 0.17.0
* refactor: Include path to test fixtures

https://greenkeeper.io/

* chore(package): update npm-run-all to version 4.0.0 (#111)

https://greenkeeper.io/

* Update eslint-config-stylelint to the latest version 🚀 (#110)

* chore(package): update eslint-config-stylelint to version 6.0.0
* refactor: Update tests per latest `eslint-config-stylelint`

* chore: bump minimum NodeJS requirement to 6.9.1 and drop NodeJS 4.x (#118)

* chore: Drop NodeJS from Travis CI

* chore: Drop NodeJS from AppVeyor

* chore: Bump minimum NodeJS requirement to 6.9.1

* chore: Update remark and remark plugin packages (#120)

* Update ava to the latest version 🚀 (#112)

* chore(package): update ava to version 0.18.0

https://greenkeeper.io/

* chore: update ava to version 0.19.1

* Updated and removed deprecated stylelint rules for 8.0 (#116)

* Updated and removed deprecated stylelint rules

* Removed deprecated unit test

* chore: Add require NodeJS 6.x LTS changelog note

* chore: Update changelog for changes made in #116

* refactor: Switch from AVA to Jest for tests. (#122)

* tests: Fix `media-query-list-comma-space-before` tests

* refactor: Switch from AVA to Jest for tests.

* chore(package): update stylelint to version 7.10.1 (#123)

* chore(package): update stylelint-scss to version 1.4.4 (#124)

* chore(package): update eslint to version 3.19.0 (#125)

* refactor: Switch from eslint-plugin-ava to eslint-plugin-jest. (#126)

* refactor: Switch from eslint-plugin-ava to eslint-plugin-jest.

* docs: Add changelog entry for switch from eslint-plugin-ava to eslint-plugin-jest

* Fixed: Added `stylelint-scss` plugin @if/@else placement rules. (#127)

* fix: Ignore proprietary `DXImageTransform.Microsoft` MS filters (#128)

* docs: Update CHANEGLOG

* Merge branch 'master' of github.com:ntwb/stylelint-config-wordpress

* feat: Prepare `10.0.0` release.

* fix: Remove stylelint v8 deprecated rule `rule-non-nested-empty-line-before` from SCSS config. (#130)

* feat: Prepare `10.0.1` release.

* fix: Add `@import` to `ignoreAtRules` option in `at-rule-empty-line-before` rule for SCSS config (#131)

* feat: Prepare `10.0.2` release.

* chore(package): update eslint-plugin-jest to version 20.0.0 (#134)

* chore(package): update jest to version 20.0.0 (#135)

* docs: Update docs to reflect the new repository home

* docs: Update docs to reflect the new repository home at https://github.com/WordPress-Coding-Standards

* chore: Update changelog noting repo location change

* fix: Add `declaration-property-unit-whitelist` rule to enforce unitless `line-height` values. (#133)

* fix: Include CSS config `at-rule-empty-line-before` options in SCSS config. (#139)

* Fix: Allow `px` units in `line-height` values for the `declaration-property-unit-whitelist` rule. (#140)

* feat: Prepare `11.0.0` release.

* Updated README section links (#141)

* chore: Add NodeJS v8 to Travis CI build matrix (#143)

* chore: Switch from Node.js "current v7.x branch to v8.x for AppVeyor CI (#145)

* chore: Drop Node.js v7.x branch from Travis CI (#146)

* refactor: Switch to shared `recommended` config from `eslint-plugin-wordpress` for ESLint configuration. (#147)

* refactor: Switch to shared `recommended` config from `eslint-plugin-wordpress` for ESLint configuration.

* chore: Use `git://` protocol

* chore: Include a commit hash

* chore: Update ESLint to version 4.1.0

* chore: Update ESLint to version 4.x

* refactor: Update indentation per updated ESLint version 4.x `indent` rule.

* chore: Add a `dry-release` npm task (#149)

* chore: Move ESLint config from `package.json` to `.eslintrc.json` file. (#152)

* chore: Use the latest npm for all Node.js Travis CI jobs

* chore: Add npm 5's `package-lock.json` file

* chore: Add Greenkeeper support for npm 5.x's `package-lock.json` file.

* tests: Add Jest snapshot tests

* tests: Update Jest snapshots

* chore(package): update stylelint to version 8.0.0

* fix: Add initial support for long comments in headers of WordPress theme `style.css` files. (#151)

This change allows for longer comments in themes header:
• URLs longer than 80 characters
• Descriptions longer than 80 characters
• Tags longer than 80 characters

Fixes #150.

* tests: Add some bbPress Jest snapshot tests.

* tests: Update Jest SCSS tests to use SCSS config

* tests: Update Jest SCSS test snapshots

* tests: Add some BuddyPress Jest snapshot tests.

* chore: Use the `runInBand` flag for Jest Travis CI jonbs

* tests: Update snapshots

* tests: Update tests to account for new rules introduced in `stylelint-config-recommended`.

* chore: Add `stylelint-config-recommended` extend base configuration from it.

* docs: Update CHANGELOG with `stylelint-config-recommended` changes

* docs: Remove the styleguide from the repo.

We should have one canonical source of truth and not try to maintain two instances.

https://make.wordpress.org/core/handbook/best-practices/coding-standards/css/

* refactor: Use `scss/at-rule-no-unknown` in `scss` shared config.

* feat: Prepare `12.0.0` release.

* chore(package): update remark-cli to version 4.0.0

* chore: Update `package-lock.json`

* chore(package): update remark-preset-lint-recommended to version 3.0.0

* chore: Update `package-lock.json`

* fix(package): update stylelint-scss to version 2.0.0

* chore: Update `package-lock.json`

* chore: Add `stylelint-find-rules`

* chore(package): update stylelint-find-rules to version 1.0.1

Closes #168

* chore: Update package-lock.json

* chore: Updated `stylelint` peer dependency version to `^8.0.0`.

* chore(package): update jest to version 21.0.0

* chore: Update `package-lock.json`

* chore(package): update eslint-plugin-jest to version 21.0.0

* chore: Update `package-lock.json`

* tests: Remove Jest snapshots (#176)

* docs: Update CHANGELOG

* Use toHaveLength() in tests

Not only does it check the length of something is exactly a certain integer, it also checks that the length property exists in the first place.

Addresses lint issues identified at https://www.bithound.io/github/WordPress-Coding-Standards/stylelint-config-wordpress/e2bbe0d9c867cc95da6de5b3bff2a73742135fb6/files#failing

* chore: Remove Greenkeeper lock file configuration from `.travis.yml`

* chore: Remove `package-lock.json`

* chore: Add `package-lock.json` to `.gitignore`

* chore: Add `.npmrc` file to prevent npm creating a `packake-lock.json` file.

* chore(package): update jest to version 22.0.0

* chore: update `.editorconfig` per upstream WordPress' `.eitorconfig`

See https://core.trac.wordpress.org/browser/trunk/.editorconfig

* chore: use tabs for indentaion in `package.json` per WordPress coding standards

* chore: use tabs for indentaion in `.eslintrc.json` per WordPress coding standards

* chore: use `* text=auto` in `.gitattributes`

* chore(package): update remark-cli to version 5.0.0

* chore: standardize Jest tests

* chore: add commitlint

* chore: bump minimum Nod.js required version to `8.9.3`

* test: improved `no-duplicate-selectors` tests

* feat: update `stylelint` to `9.1.3`

* chore: updated `stylelint-config-recommended` to `2.1.0`

* chore: updated: `stylelint-scss` to `2.1.0`

* feat: update `selector-pseudo-element-colon-notation` to use `double`

* feat: prepare `13.0.0` release

* fix(package): update stylelint-scss to version 3.0.0

* docs: update changelog

* test: add SCSS tests for _extends_ shared configs

This test ensures that the rules included in the _shared configs_ inherited by this SCSS _shared config_ via the `extends` option are in actual fact included.

The `stylelint-config-wordpress/scss` shared config _extends_ the `stylelint-config-wordpress` shared config, which in turn _extends_ the `stylelint-config-recommended` shared config.

* docs: update changelog

* test: standardize invalid tests warnings test name verbiage

* test: use Jest snapshots for invalid tests

This change simplifies the maintainence of the invalid CSS and SCSS tests

* feat: the `/scss` config now extends `stylelint-config-recommended-scss`

* feat: update `stylelint` to `9.2.0`

* docs: add basic _extends_ shared config references

* Update to node 10 in .travis.yml

* Drop Node.js v9.x

* Update appveyor.yml

* chore(package): update @commitlint/cli to version 7.0.0

* chore(package): update @commitlint/config-conventional to version 7.0.1 (#203)

Closes #201

* chore(package): update npmpub to version 4.0.1

Closes #204

* feat: update stylelint to `9.5.0`

* chore: update ESLint to `5.4.0`

* chore: update Jest to `23.5.0`

* chore: update `eslint-plugin-jest` to `21.21.0`

* chore: update `npmpub` to `4.1.0`

* chore: update `npm-run-all` to `4.1.3`

* chore: update `stylelint-find-rules` to `1.1.1`

* chore: update remark presets: • `remark-preset-lint-consistent` to `2.0.2` • `remark-preset-lint-recommended` to `3.0.2`

* feat: update `stylelint-scss` to `3.3.0`

* chore: add `npm-package-json-lint`

* chore: add `@wordpress/npm-package-json-lint-config`

* chore: update `package.json` property order

* feat: Prepare `13.1.0` release (#208)

* chore(package): update husky to version 1.1.2 (#210)

Closes #209

* chore(package): update remark-cli to version 6.0.0 (#211)

* chore(package): update eslint-plugin-jest to version 22.0.0 (#212)

* Update stylelint-find-rules to the latest version 🚀 (#213)

## The devDependency [stylelint-find-rules](https://github.com/alexilyaev/stylelint-find-rules) was updated from `1.1.1` to `2.0.0`.
This version is **not covered** by your **current version range**.

If you don’t accept this pull request, your project will work just like it did before. However, you might be missing out on a bunch of new features, fixes and/or performance improvements from the dependency update.

* chore(package): update stylelint to version 10.0.1 (#215)

Closes #214

* chore: update @commitlint

* chore: update `stylelint-config-recommended` to v2.2.0

* chore: update `stylelint-scss` to v3.6.0

* chore: update devDependencies

* feat: prepare `14.0.0` release

* chore(package): update husky to version 2.2.0

Closes #219

* chore: update `husky.hooks` config in `package.json`

* chore(package): update @wordpress/npm-package-json-lint-config to version 2.0.0

* chore(package): update husky to version 3.0.1

Closes #227

* test: fix type in snapshot test

* chore(package): update @commitlint/cli to version 8.0.0

* chore(package): update @commitlint/config-conventional to version 8.0.0

* chore(package): update remark-cli to version 7.0.0

* chore(package): update packages to latest versions

* chore(package): restore peerDependencies stylelint versions

* chore(node): bump minimum Node.JS to LTS version 10.x

* ci: use `npm test` to include lint tasks in CI jobs

* docs: nocapital_S_dangit

* chore(package): update npmpub to version 5.0.0

* fix(package): update stylelint-config-recommended to version 3.0.0

* chore(package): update stylelint to version 11.0.0

* chore: update `peerDependencies` for stylelint 11.0.0

* docs: update changelog

* docs: fix stylelint removed compat version

* Update stylelint-config-recommended-scss to the latest version 🚀 (#238)

* Update eslint to the latest version 🚀 (#233)

* chore(package): update eslint to version 6.3.0

* chore: add `ecmaVersion: 2015,` to `parserOptions` ESLint config

* docs: update changelog

* chore: bump dependencies

* chore: add Node.js v12 to Travis CI test matrix, remove 8.x, min 10.x

chore: add Node.js v12 to Travis CI test matrix

* feat: prepare `15.0.0` release

* Merge pull request #241 from WordPress-Coding-Standards/update/find-rules

chore: update `stylelint-find-rules` to 2.2.0

* Update npm-package-json-lint to the latest version 🚀 (#242)

Update npm-package-json-lint to the latest version 🚀

* Use `@wordpress/scripts` (#231)

Use `@wordpress/scripts`

* chore: update `stylelint` to 12.0.0

* chore: update `stylelint-scss` to 3.13.0

* chore: update `stylelint-config-recommended-scss` to 4.1.0

* chore: update `husky` to 3.1.0

* chore: update `remark-cli` to 7.0.1

* chore: update `@wordpress/scripts` to 6.0.0

* Fixed: `selector-class-*` regex to account for numerals, case de… (#247)

Fixed: `selector-class-*` regex to account for numerals, case detection, and ensure kebab-case

* ci: add Windows to Travis CI (#248)

ci: add Windows to Travis CI

* chore: remove AppVeyor (#249)

chore: remove AppVeyor

* feat: prepare `16.0.0` release

* test: update comment fof scss-invalid test to eslint-jsdoc warnings

* feat: prepare `16.0.0` release

* fix: npm script temp workaround

* Merge pull request #251 from WordPress-Coding-Standards/greenkeeper/@wordpress/scripts-6.1.1

chore(package): update @wordpress/scripts to version 6.1.1

* Revert "fix: npm script temp workaround"

This reverts commit e409112e0e8f3965993e3f1b3a6ecc3c8ffdc8e0.

* Update husky to the latest version 🚀 (#252)

Update husky to the latest version 🚀

* Merge pull request #255 from WordPress-Coding-Standards/greenkeeper/stylelint-13.1.0

Update stylelint to the latest version 🚀

* Merge pull request #254 from WordPress-Coding-Standards/greenkeeper/@wordpress/scripts-7.0.0

Update @wordpress/scripts to the latest version 🚀

* chore(package): update @wordpress/scripts to version 7.1.2

* chore(package): update stylelint-scss to version 3.14.2

* chore(package): update stylelint-config-recommended-scss to version 4.2.0

* chore(package): update husky to version 4.2.3

* chore(package): update @commitlint/cli to version 8.3.5

* chore(package): update @commitlint/config-conventional to version 8.3.4

* Merge pull request #256 from WordPress-Coding-Standards/greenkeeper/remark-cli-8.0.0

Update remark-cli to the latest version 🚀

* Merge pull request #258 from WordPress-Coding-Standards/greenkeeper/remark-preset-lint-recommended-4.0.0

Update remark-preset-lint-recommended to the latest version 🚀

* Merge pull request #257 from WordPress-Coding-Standards/greenkeeper/remark-preset-lint-consistent-3.0.0

Update remark-preset-lint-consistent to the latest version 🚀

* Merge pull request #260 from WordPress-Coding-Standards/greenkeeper/@wordpress/scripts-8.0.1

* Merge pull request #264 from WordPress-Coding-Standards/greenkeeper/@wordpress/scripts-10.0.0

chore(package): update @wordpress/scripts to version 10.0.0

* chore: update `stylelint-scss` to 3.17.2

* feat: prepare `17.0.0` release

* refactor: rename `stylelint-config-wordpress` to `stylelint-config`

* refactor: rename `stylelint-config-wordpress` to `@wordpress/stylelint-config` in `package.json`

* refactor: remove `@commitlint` from `@wordpress/stylelint-config`

* refactor: remove `husky` from `@wordpress/stylelint-config`

* refactor: trim npm package keywords from `@wordpress/stylelint-config`

* refactor: remove `.editorconfig` from `@wordpress/stylelint-config`

* refactor: remove `npmpub` from `@wordpress/stylelint-config`

* refactor: remove `eslintConfig` from `@wordpress/stylelint-config`

* refactor: remove `remarkConfig` from `@wordpress/stylelint-config`

* refactor: remove `remark` from `@wordpress/stylelint-config`

* refactor: remove `engines` from `@wordpress/stylelint-config`

* refactor: remove `prettier.config.js` from `@wordpress/stylelint-config`

* refactor: remove `.gitattributes` from `@wordpress/stylelint-config`

* refactor: remove `.gitignore` from `@wordpress/stylelint-config`

* refactor: remove `.travis.yml` from `@wordpress/stylelint-config`

* tests: refactor tests in `@wordpress/stylelint-config`

* chore: add `.stylelintignore` for _invalid_ scss test fixtures in `@wordpress/stylelint-config`

* Revert "chore: add `.stylelintignore` for _invalid_ scss test fixtures in `@wordpress/stylelint-config`"

This reverts commit 05ab441.

* chore: add `.stylelintrc.json` for test fixtures in `@wordpress/stylelint-config`

* tests: update Jest snapshots in `@wordpress/stylelint-config`

* docs: update `docs/manifest.json` for `@wordpress/stylelint-config`

* chore: update `@wordpress/stylelint-config` package description

* chore: remove `devDependencies` from `@wordpress/stylelint-config`

* chore: remove package `scripts` from `@wordpress/stylelint-config`

* chore: remove superfluous `.stylelintignore` from `@wordpress/stylelint-config`

* chore: add Lerna `publishConfig` to `@wordpress/stylelint-config`

* Update Jest snapshots

* Backfill release dates in changelog

* Update package author

* Update readme

* Update comment to use renamed package name

* Rename tests to match other packages

* Remove stylelint `^10.1.0`, `^11.0.0`, and `^12.0.0` as peer dependency.

Co-authored-by: greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>
Co-authored-by: Harley Oliver <harleyoliver@users.noreply.github.com>
Co-authored-by: Heather B <heatherbrokmeier@gmail.com>
Co-authored-by: Gary Jones <gary@gamajo.com>
Co-authored-by: greenkeeper[bot] <23040076+greenkeeper[bot]@users.noreply.github.com>
Co-authored-by: Dominik Schilling <dominikschilling+git@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Task Issues or PRs that have been broken down into an individual action to take [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible