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

Block comparison: show difference between invalid block conversion options #7995

Merged
merged 12 commits into from Sep 13, 2018

Conversation

Projects
None yet
4 participants
@johngodley
Contributor

johngodley commented Jul 17, 2018

Description

When you have an invalid block the result of the available actions can be unknown.

edit_post_ wordpress_latest _wordpress

This PR adds a 'compare conversion' option that shows the actual HTML difference when 'convert to blocks' is applied.

The difference appears in a modal and the user can select to keep the current contents or apply the conversion, with full knowledge of the result of their action.

another_post___ wordpress_latest _wordpress

The modal adjusts to the height of the block:

edit_post_ wordpress_latest _wordpress

Overflowing, if too tall, and scrollable:

edit_post_ wordpress_latest _wordpress

And adjusts accordingly on smaller screens (using overflow scroll if too tall):

edit_post_ wordpress_latest _wordpress

Note: this is based on the discussion in #7604

How has this been tested?

  1. Manually check that the 'compare conversion' option displays correctly for different types of blocks and at different screen sizes
  2. Manually verify that the 'keep as HTML' converts the block to an HTML block
  3. Manually verify that the 'convert to blocks' applies a conversion identical to picking 'convert to blocks' from the invalid block modal

Types of changes

This adds a new feature.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 2, 2018

Contributor

Noting that the comparison currently uses code from jsdiff to perform proper diffing. This is a BSD licensed open source library. It works well, but we don't need the entire library. I'm unsure about the best route for proceeding here, and I don't know if it's appropriate to include the library as-is, or the full package.

While Gutenberg does have it's own HTML parsing, and also HTML comparison (via isEquivalentHTML), it's doesn't find the longest common sequences, and would result in a poor diff that would need adapting to a proper diffing algorithm.

An alternative is to re-implement jsdiff ourselves.

Open to suggestions.

Contributor

johngodley commented Sep 2, 2018

Noting that the comparison currently uses code from jsdiff to perform proper diffing. This is a BSD licensed open source library. It works well, but we don't need the entire library. I'm unsure about the best route for proceeding here, and I don't know if it's appropriate to include the library as-is, or the full package.

While Gutenberg does have it's own HTML parsing, and also HTML comparison (via isEquivalentHTML), it's doesn't find the longest common sequences, and would result in a poor diff that would need adapting to a proper diffing algorithm.

An alternative is to re-implement jsdiff ourselves.

Open to suggestions.

@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 2, 2018

Contributor

Also noting that the style is a best attempt at matching that proposed in #7604, but needs some improving. @jasmussen I'd very much appreciate any suggestions/help you can give.

In particular I assumed that we would want to show deleted characters in the right panel, and I've included these in red. We can not show those at all, if it makes more sense.

Contributor

johngodley commented Sep 2, 2018

Also noting that the style is a best attempt at matching that proposed in #7604, but needs some improving. @jasmussen I'd very much appreciate any suggestions/help you can give.

In particular I assumed that we would want to show deleted characters in the right panel, and I've included these in red. We can not show those at all, if it makes more sense.

@jasmussen

This comment has been minimized.

Show comment
Hide comment
@jasmussen

jasmussen Sep 3, 2018

Contributor

Sorry I completely missed this. Feel free to assign me as a reviewer next time and I'll be sure to get to it. I'll try and take a look today, maybe push code.

Contributor

jasmussen commented Sep 3, 2018

Sorry I completely missed this. Feel free to assign me as a reviewer next time and I'll be sure to get to it. I'll try and take a look today, maybe push code.

@jasmussen jasmussen self-requested a review Sep 3, 2018

@jasmussen

This comment has been minimized.

Show comment
Hide comment
@jasmussen

jasmussen Sep 5, 2018

Contributor

@johngodley This is impressive work. I think it's super duper solid, and it's VERY much good enough to get into master so we can iterate.

I pushed a small fix so it only scrolls when necessary, and I made the menu option titlecase.

Can you rebase this?

Question: does this use the modal API? Assuming yes as it really seems to be, which is great, just verifying.

Contributor

jasmussen commented Sep 5, 2018

@johngodley This is impressive work. I think it's super duper solid, and it's VERY much good enough to get into master so we can iterate.

I pushed a small fix so it only scrolls when necessary, and I made the menu option titlecase.

Can you rebase this?

Question: does this use the modal API? Assuming yes as it really seems to be, which is great, just verifying.

@johngodley johngodley changed the title from WIP - Block comparison: show difference between invalid block conversion options to Block comparison: show difference between invalid block conversion options Sep 5, 2018

@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 5, 2018

Contributor

does this use the modal API

If you mean <Modal /> then yep it does.

Rebased. There's a codecov failure which I don't understand as the unit test coverage has increased.

I've noticed some problems with a few of the more esoteric blocks so I'll look at fixing those.

Contributor

johngodley commented Sep 5, 2018

does this use the modal API

If you mean <Modal /> then yep it does.

Rebased. There's a codecov failure which I don't understand as the unit test coverage has increased.

I've noticed some problems with a few of the more esoteric blocks so I'll look at fixing those.

@johngodley johngodley changed the title from Block comparison: show difference between invalid block conversion options to WIP: Block comparison: show difference between invalid block conversion options Sep 5, 2018

@jasmussen

This comment has been minimized.

Show comment
Hide comment
@jasmussen

jasmussen Sep 6, 2018

Contributor

If you mean then yep it does.

Yes, awesome!

I'm extending the review range and adding a milestone so we can get this in. Amazing work! This is a KILLER feature.

Contributor

jasmussen commented Sep 6, 2018

If you mean then yep it does.

Yes, awesome!

I'm extending the review range and adding a milestone so we can get this in. Amazing work! This is a KILLER feature.

@jasmussen jasmussen requested a review from WordPress/gutenberg-core Sep 6, 2018

@jasmussen jasmussen added this to the 3.9 milestone Sep 6, 2018

johngodley and others added some commits Jul 17, 2018

Add block compare component
Shows two blocks side by side with the difference in HTML highlighted
Block wanring: add comparison option
Use the block comparison component to show the difference between the invalid block options in a modal
Fix line heights for deleted content
If a deleted content span went over onto the next line it would overlap with other spans
@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 6, 2018

Contributor

I made a some small tweaks to the CSS regarding line height. If you had a deleted section wrapping over lines it could overlap:

edit_post_ wordpress_latest _wordpress

This has now been fixed.

I noticed two other problems:

  • The Modal component doesn't prevent focus/blur events from propagating through to the page underneath. This means you can trigger tooltips and block dropdown menus, making it a bit twitchy feeling. I've got a fix in place which I'll put in a separate PR
  • Some blocks don't behave well to 'convert to blocks', and can result in the entire block being deleted. This isn't caused by the code here, but the preview ability makes it more noticeable. I'll also look at this separately
Contributor

johngodley commented Sep 6, 2018

I made a some small tweaks to the CSS regarding line height. If you had a deleted section wrapping over lines it could overlap:

edit_post_ wordpress_latest _wordpress

This has now been fixed.

I noticed two other problems:

  • The Modal component doesn't prevent focus/blur events from propagating through to the page underneath. This means you can trigger tooltips and block dropdown menus, making it a bit twitchy feeling. I've got a fix in place which I'll put in a separate PR
  • Some blocks don't behave well to 'convert to blocks', and can result in the entire block being deleted. This isn't caused by the code here, but the preview ability makes it more noticeable. I'll also look at this separately
@jasmussen

This comment has been minimized.

Show comment
Hide comment
@jasmussen

jasmussen Sep 6, 2018

Contributor

The Modal component doesn't prevent focus/blur events from propagating through to the page underneath. This means you can trigger tooltips and block dropdown menus, making it a bit twitchy feeling. I've got a fix in place which I'll put in a separate PR

🏅

Yeah this is a separate issue that would be sweet to fix.

Some blocks don't behave well to 'convert to blocks', and can result in the entire block being deleted. This isn't caused by the code here, but the preview ability makes it more noticeable. I'll also look at this separately

You rule the world.

Contributor

jasmussen commented Sep 6, 2018

The Modal component doesn't prevent focus/blur events from propagating through to the page underneath. This means you can trigger tooltips and block dropdown menus, making it a bit twitchy feeling. I've got a fix in place which I'll put in a separate PR

🏅

Yeah this is a separate issue that would be sweet to fix.

Some blocks don't behave well to 'convert to blocks', and can result in the entire block being deleted. This isn't caused by the code here, but the preview ability makes it more noticeable. I'll also look at this separately

You rule the world.

Fix flexbox spacing when converted preview is smaller
The vertical spacing would become strange if the converted preview was shorter than the original preview

@johngodley johngodley changed the title from WIP: Block comparison: show difference between invalid block conversion options to Block comparison: show difference between invalid block conversion options Sep 6, 2018

@johngodley johngodley referenced this pull request Sep 6, 2018

Merged

Update invalid block copy #9667

0 of 4 tasks complete
@talldan

@johngodley - This is really cool. In fact, I think it's so useful I was wondering if we would want to make it more prominent?

I added some comments, I think the main one that needs to be fixed is the max-height: 70% issue which is visible to the user.

Will probably also need someone more knowledgeable to comment on the library inclusion. Not sure who would be best.

Show outdated Hide outdated packages/editor/src/components/block-compare/index.js Outdated
Show outdated Hide outdated packages/editor/src/components/block-compare/index.js Outdated
Show outdated Hide outdated packages/editor/src/components/block-compare/index.js Outdated
Show outdated Hide outdated packages/editor/src/components/block-compare/index.js Outdated
Show outdated Hide outdated packages/editor/src/components/block-compare/style.scss Outdated
Show outdated Hide outdated packages/editor/src/components/block-compare/style.scss Outdated
}
}
.editor-block-compare__converted {

This comment has been minimized.

@talldan

talldan Sep 7, 2018

Contributor

Do we have any thoughts on nesting element selectors inside the block selector @jasmussen? It might introduce unnecessary specificity, but then I'm not sure if we'd expect to have other styles try to override these, so probably ok.

One option is to do &__converted and in the resulting css the parent selector won't be included, but that only works one level deep.

@talldan

talldan Sep 7, 2018

Contributor

Do we have any thoughts on nesting element selectors inside the block selector @jasmussen? It might introduce unnecessary specificity, but then I'm not sure if we'd expect to have other styles try to override these, so probably ok.

One option is to do &__converted and in the resulting css the parent selector won't be included, but that only works one level deep.

Show outdated Hide outdated packages/editor/src/components/block-compare/style.scss Outdated
if ( compare ) {
return (
<Modal

This comment has been minimized.

@talldan

talldan Sep 7, 2018

Contributor

Just some food for thought - I think I would have approached this differently and made BlockCompareModal a component that manages its own open/closed state. I'm not sure there's a right or wrong.

@talldan

talldan Sep 7, 2018

Contributor

Just some food for thought - I think I would have approached this differently and made BlockCompareModal a component that manages its own open/closed state. I'm not sure there's a right or wrong.

This comment has been minimized.

@johngodley

johngodley Sep 7, 2018

Contributor

Yeah, it's a good point. My thinking is that the comparison component could (potentially, and currently without any need) be used elsewhere that might be outside of a modal or an on/off situation and so I made the component do it's thing, and left it up to the parent to decide when to show it.

@johngodley

johngodley Sep 7, 2018

Contributor

Yeah, it's a good point. My thinking is that the comparison component could (potentially, and currently without any need) be used elsewhere that might be outside of a modal or an on/off situation and so I made the component do it's thing, and left it up to the parent to decide when to show it.

johngodley added some commits Sep 7, 2018

Remove max height
It’s not necessary for anything and makes the modal too small on mobile
@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 7, 2018

Contributor

I think it's so useful I was wondering if we would want to make it more prominent?

Thanks for the review @talldan. I do wonder if it might make more sense if the 'convert to blocks' button just defaults to showing the comparison component directly, and we remove the option from the dropdown menu?

The effect of 'convert to blocks' is unknown to the user, and sometimes quite arbitrary and destructive. At the point the user is being presented with this warning I don't think it's excessive to add an additional click in the process. It saves having to undo the action and being annoyed at Gutenberg if the conversion isn't as expected.

Contributor

johngodley commented Sep 7, 2018

I think it's so useful I was wondering if we would want to make it more prominent?

Thanks for the review @talldan. I do wonder if it might make more sense if the 'convert to blocks' button just defaults to showing the comparison component directly, and we remove the option from the dropdown menu?

The effect of 'convert to blocks' is unknown to the user, and sometimes quite arbitrary and destructive. At the point the user is being presented with this warning I don't think it's excessive to add an additional click in the process. It saves having to undo the action and being annoyed at Gutenberg if the conversion isn't as expected.

Restore flex for vertical spacing of elements
Without this the button doesnt stick to the bottom
@talldan

This comment has been minimized.

Show comment
Hide comment
@talldan

talldan Sep 10, 2018

Contributor

@johngodley This is looking good. I've spotted one additional thing here:
https://github.com/WordPress/gutenberg/pull/7995/files#r216273361

I think the only thing we need now is to confirm that the script/dependency inclusion is ok. (edit: worth noting that at least if we use an npm package, the licence is checked by the licence-checker script: #8808).

On the user experience, I feel like it could definitely be iterated on this so that it's part of the workflow when editing a block HTML:

  1. User edits block HTML
  2. The diff is present to them when they've finished editing with the two options.
  3. User decides an option.

There are other times when the user might end up with invalid html (e.g. using the classic editor), so we might present that slightly differently to what I've proposed above. Would be good to get additional input on this though.

Contributor

talldan commented Sep 10, 2018

@johngodley This is looking good. I've spotted one additional thing here:
https://github.com/WordPress/gutenberg/pull/7995/files#r216273361

I think the only thing we need now is to confirm that the script/dependency inclusion is ok. (edit: worth noting that at least if we use an npm package, the licence is checked by the licence-checker script: #8808).

On the user experience, I feel like it could definitely be iterated on this so that it's part of the workflow when editing a block HTML:

  1. User edits block HTML
  2. The diff is present to them when they've finished editing with the two options.
  3. User decides an option.

There are other times when the user might end up with invalid html (e.g. using the classic editor), so we might present that slightly differently to what I've proposed above. Would be good to get additional input on this though.

@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 11, 2018

Contributor

Thanks for that link, and it's pushed me towards just bundling the module normally

Contributor

johngodley commented Sep 11, 2018

Thanks for that link, and it's pushed me towards just bundling the module normally

@@ -0,0 +1,28 @@
/**

This comment has been minimized.

@aduth

aduth Sep 11, 2018

Member

I'm a bit hesitant about including a component BlockCompare in the components package, since it's not as general-purpose as intended by the package, but rather domain-specific to the idea of WordPress editors. Was editors considered instead?

@aduth

aduth Sep 11, 2018

Member

I'm a bit hesitant about including a component BlockCompare in the components package, since it's not as general-purpose as intended by the package, but rather domain-specific to the idea of WordPress editors. Was editors considered instead?

This comment has been minimized.

@johngodley

johngodley Sep 12, 2018

Contributor

I'm not sure what you mean by editors - can you point me in the direction?

@johngodley

johngodley Sep 12, 2018

Contributor

I'm not sure what you mean by editors - can you point me in the direction?

This comment has been minimized.

@jasmussen

jasmussen Sep 12, 2018

Contributor

Can't speak for Andrew but since he's asleep I'll take an educated guess. Maybe he meant edit-post?

screen shot 2018-09-12 at 10 49 29

@jasmussen

jasmussen Sep 12, 2018

Contributor

Can't speak for Andrew but since he's asleep I'll take an educated guess. Maybe he meant edit-post?

screen shot 2018-09-12 at 10 49 29

This comment has been minimized.

@johngodley

johngodley Sep 12, 2018

Contributor

Ah ok. I'm not entirely clear on the difference between editor and WordPress editors components. Are you suggesting it work like the keyboard shortcuts modal and isModalActive?

If the concern is the general purposeness of the component then could it be made local to the invalid warning component? I'm not sure if modals are designed to be used locally like this as the only other one I can find is the keyboard shortcut modal, which is 'global'.

@johngodley

johngodley Sep 12, 2018

Contributor

Ah ok. I'm not entirely clear on the difference between editor and WordPress editors components. Are you suggesting it work like the keyboard shortcuts modal and isModalActive?

If the concern is the general purposeness of the component then could it be made local to the invalid warning component? I'm not sure if modals are designed to be used locally like this as the only other one I can find is the keyboard shortcut modal, which is 'global'.

This comment has been minimized.

@jasmussen

jasmussen Sep 12, 2018

Contributor

Again I can't but make educated guesses — I think it's something about the packages getting published on NPM but not sure.

@jasmussen

jasmussen Sep 12, 2018

Contributor

Again I can't but make educated guesses — I think it's something about the packages getting published on NPM but not sure.

This comment has been minimized.

@talldan

talldan Sep 12, 2018

Contributor

I'll wait for Andrew to clarify, but the component is already in the editor package, not in the components package, so maybe it was a misread. Or maybe he did mean edit-post, but I'm not sure we should be implementing components from edit-post in editor like this would be.

@talldan

talldan Sep 12, 2018

Contributor

I'll wait for Andrew to clarify, but the component is already in the editor package, not in the components package, so maybe it was a misread. Or maybe he did mean edit-post, but I'm not sure we should be implementing components from edit-post in editor like this would be.

This comment has been minimized.

@aduth

aduth Sep 12, 2018

Member

Oof, I'm sorry for the trouble, it was definitely a misread on my part.

I had mistaken it as being part of packages/components.

@aduth

aduth Sep 12, 2018

Member

Oof, I'm sorry for the trouble, it was definitely a misread on my part.

I had mistaken it as being part of packages/components.

@talldan

This is really close, I just spotted one thing in further testing. Will also wait for @aduth to clarify his comment.

return {
rawContent: block.originalContent,
renderedContent: getSaveElement( blockType, block.attributes ),

This comment has been minimized.

@talldan

talldan Sep 12, 2018

Contributor

I've just given this another test, and I'm not sure the original content's preview displays quite what I was expecting. My steps:

  1. Add some simple text to a paragraph block
  2. Edit the html and add an inline style style="font-size:25px;"
  3. View the comparison
  4. Note that the original content preview doesn't show the font size at 25px, which is what I'd get if I selected 'Keep as HTML'.

To make the preview display correctly I tried using RawHTML like the HTML block does for its preview, which seemed to do the trick:

	getOriginalContent( block ) {
		return {
			rawContent: block.originalContent,
			renderedContent: (
				<RawHTML>{ block.originalContent }</RawHTML>
			),
		};
	}
@talldan

talldan Sep 12, 2018

Contributor

I've just given this another test, and I'm not sure the original content's preview displays quite what I was expecting. My steps:

  1. Add some simple text to a paragraph block
  2. Edit the html and add an inline style style="font-size:25px;"
  3. View the comparison
  4. Note that the original content preview doesn't show the font size at 25px, which is what I'd get if I selected 'Keep as HTML'.

To make the preview display correctly I tried using RawHTML like the HTML block does for its preview, which seemed to do the trick:

	getOriginalContent( block ) {
		return {
			rawContent: block.originalContent,
			renderedContent: (
				<RawHTML>{ block.originalContent }</RawHTML>
			),
		};
	}

This comment has been minimized.

@johngodley

johngodley Sep 12, 2018

Contributor

Interesting!

RawHTML uses dangerouslySetInnerHTML, which opens up things like <p onclick="alert(1)">fdsfsdfds fd sfds</p>. I'm not sure if this is a problem in this context and what the behaviour is supposed to be so I'll have a poke around.

@johngodley

johngodley Sep 12, 2018

Contributor

Interesting!

RawHTML uses dangerouslySetInnerHTML, which opens up things like <p onclick="alert(1)">fdsfsdfds fd sfds</p>. I'm not sure if this is a problem in this context and what the behaviour is supposed to be so I'll have a poke around.

This comment has been minimized.

@johngodley

johngodley Sep 12, 2018

Contributor

The 'preview' mode of the HTML block uses the <Sandbox /> component to display arbitrary HTML, which neutralises my above example, and seems to be the way to go. The styling is different so I'll see if it can be made to fit in.

@johngodley

johngodley Sep 12, 2018

Contributor

The 'preview' mode of the HTML block uses the <Sandbox /> component to display arbitrary HTML, which neutralises my above example, and seems to be the way to go. The styling is different so I'll see if it can be made to fit in.

This comment has been minimized.

@johngodley

johngodley Sep 12, 2018

Contributor

After some playing around it seems <Sandbox /> is an iframe and while it does prevent the JS above, it is also unstyled.

Although I think the scope for mischief is small I'm not sure we should introduce it.

With that in mind we can either accept the unstyled appearance (looks ok for paragraphs, doesnt look ok for images), or keep the current not-quite-full preview (it's displaying the block without the invalid bits, but with the valid changes). There may be another way I'm unaware of, too

@johngodley

johngodley Sep 12, 2018

Contributor

After some playing around it seems <Sandbox /> is an iframe and while it does prevent the JS above, it is also unstyled.

Although I think the scope for mischief is small I'm not sure we should introduce it.

With that in mind we can either accept the unstyled appearance (looks ok for paragraphs, doesnt look ok for images), or keep the current not-quite-full preview (it's displaying the block without the invalid bits, but with the valid changes). There may be another way I'm unaware of, too

This comment has been minimized.

@talldan

talldan Sep 12, 2018

Contributor

Hmm, yep, thanks for looking into it. Lets go with what we've got and then maybe look into this on a separate issue.

@talldan

talldan Sep 12, 2018

Contributor

Hmm, yep, thanks for looking into it. Lets go with what we've got and then maybe look into this on a separate issue.

@johngodley johngodley merged commit 5ea0283 into master Sep 13, 2018

2 checks passed

codecov/project 48.94% (-0.24%) compared to 694a19b
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@johngodley

This comment has been minimized.

Show comment
Hide comment
@johngodley

johngodley Sep 13, 2018

Contributor

Thanks for the feedback and suggestions!

Contributor

johngodley commented Sep 13, 2018

Thanks for the feedback and suggestions!

@johngodley johngodley deleted the add/invalid-block-diff branch Sep 13, 2018

@jasmussen

This comment has been minimized.

Show comment
Hide comment
@jasmussen

jasmussen Sep 13, 2018

Contributor

Amazing work!

Contributor

jasmussen commented Sep 13, 2018

Amazing work!

return (
<div className={ className }>
<div className="editor-block-compare__content">
<h1 className="components-modal__header-heading">{ title }</h1>

This comment has been minimized.

@aduth

aduth Sep 13, 2018

Member

This is not the modal component, so should not be stealing / inheriting styles. Components should be insulated from one another to avoid maintenance issues with cascading consequences of future changes.

@aduth

aduth Sep 13, 2018

Member

This is not the modal component, so should not be stealing / inheriting styles. Components should be insulated from one another to avoid maintenance issues with cascading consequences of future changes.

</div>
<div className="editor-block-compare__action">
<Button isLarge tabindex="0" onClick={ action }>{ actionText }</Button>

This comment has been minimized.

@aduth

aduth Sep 13, 2018

Member

I'm guessing a console warning is being logged on this line?

We should pass tabIndex as the DOM property tabIndex={ 0 }, not the attribute name.

Note that you should still use the canonical React naming for known attributes:

// Yes, please
<div tabIndex="-1" />

// Warning: Invalid DOM property `tabindex`. Did you mean `tabIndex`?
<div tabindex="-1" />

In other words, the way you use DOM components in React hasn’t changed, but now you have some new capabilities.

https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html

@aduth

aduth Sep 13, 2018

Member

I'm guessing a console warning is being logged on this line?

We should pass tabIndex as the DOM property tabIndex={ 0 }, not the attribute name.

Note that you should still use the canonical React naming for known attributes:

// Yes, please
<div tabIndex="-1" />

// Warning: Invalid DOM property `tabindex`. Did you mean `tabIndex`?
<div tabindex="-1" />

In other words, the way you use DOM components in React hasn’t changed, but now you have some new capabilities.

https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html

This comment has been minimized.

@johngodley

johngodley Sep 13, 2018

Contributor

Oddly it doesn't log a warning, but both very valid points and I'll get those fixed in another PR

@johngodley

johngodley Sep 13, 2018

Contributor

Oddly it doesn't log a warning, but both very valid points and I'll get those fixed in another PR

This comment has been minimized.

@johngodley
@johngodley

johngodley Sep 14, 2018

Contributor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment