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

POC: Extract Markdown links and headers as components. #613 #619

Conversation

ryanoglesby08
Copy link
Contributor

... so that they can be overridden in styleguide.config.js.

@ryanoglesby08
Copy link
Contributor Author

Re: Issue #613

@ryanoglesby08
Copy link
Contributor Author

Hi @sapegin

This is a WIP and more of a proof of concept right now. I wanted to go ahead and get a PR out there so that I can get some feedback before continuing further down this path.

My strategy is to break up the large styles object in "rsg-components/Markdown" and extract components for each element. I've done that for a and h1-h6. This will allow each Markdown element/component to be overridden using the styleguideComponents config option. When overriding the Markdown components, you will export a markdown-to-jsx config object containing the new component and any props.

I've overridden links and headers in this manner in the customised example.

This seems to be consistent with the patterns already established, flexible, allow custom theming and styles to still work, and does not introduce much extra complexity.

Let me know what you think!

@sapegin
Copy link
Member

sapegin commented Oct 2, 2017

Hey @ryanoglesby08, thank you very much for your pull request! I’m just back from React Alicante (it was amazing!) and will have a look soon ;-)

Copy link
Member

@sapegin sapegin left a comment

Choose a reason for hiding this comment

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

I like the general idea of breaking the UI into small peaces, but I think the implementation is more complex than it could be:

We already have a Link component so you can reuse it directly. I’d extract Header component the same way so it could be reused not only in Markdown. And I’m not sure we need to store these configs in separate files.

@ryanoglesby08
Copy link
Contributor Author

Re: I’d extract Header component the same way so it could be reused not only in Markdown.

Sure. I can do that eventually.


Re: And I’m not sure we need to store these configs in separate files.

By "configs" I assume you mean the mappings of component + props to the corresponding tag name that gets translated by markdown-to-jsx.

I think storing the configs in separate files enables modularity and creates a more flexible solution. By storing the configs in separate files, it allows the react component library to define its own mappings per component without having to override a giant Markdown.js file.

Overriding any Markdown element with a new component requires 2 things: 1) the new component and 2) a new mapping of the Markdown element to the component and props. If I did not keep the configs separate, it means more files need to change to override a single Markdown element.

Do you have other ideas for how I might approach this?

@sapegin
Copy link
Member

sapegin commented Oct 3, 2017

I think storing the configs in separate files enables modularity and creates a more flexible solution. By storing the configs in separate files, it allows the react component library to define its own mappings per component without having to override a giant Markdown.js file.

Do you see many use cases when people would want to define separate components for each heading level? Do you think it’s important to differentiate components (link, header, etc.) that are used in Markdown and the same components that are used in Styleguidist UI? I think using normal component (when you export a real component) increases modularity and much less surprising.

Overriding any Markdown element with a new component requires 2 things: 1) the new component and 2) a new mapping of the Markdown element to the component and props. If I did not keep the configs separate, it means more files need to change to override a single Markdown element.

In both cases you would need to override one file: file that exports component or file that exports mapping and hides component inside.

@ryanoglesby08
Copy link
Contributor Author

Hi @sapegin. I've finally been able to work a bit more on this. I've changed the approach a little bit based on your feedback. This feels like a good approach to me. Here is the structure I've come out with so far. Let me know of your feedback.

rsg-components
|
| ->Heading/HeadingRenderer.js: a h1 - h6 component used throughout styleguidist, including Markdown files (Override me to replace all headings)
|
|
|-> Markdown/Heading.js: An adapter on top of HeadingRenderer that adds bottom margin. This is useful for the prose in Markdown, but not wanted on all headings throughout the style guide, such as the SectionHeadings. (Override me to replace how much spacing is added around headings in Markdown)
|
|-> Markdown/Markdown.js: Contains the mapping of all components to elements in Markdown


examples/customised

src/components
| -> Header.js: A custom h1 - h6 component being showcased

styleguide/components
| -> Heading.js: An adapter that adapts the interface of "rsg-components/Heading/HeadingRenderer" to the Header that is being showcased. Namely adapting the depth prop to the level prop, which have different types.
| -> Link.js: A Link component to be used in the styleguide with custom link styling. This is just an example of how to incorporate plain styles and another overridden component.

styleguide.config.js
—> alias HeadingRenderer with "styleguide/components/Heading"
—> alias Link with "styleguide/components/Link"

Copy link
Member

@sapegin sapegin left a comment

Choose a reason for hiding this comment

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

I like it much more, thanks!

}

export const styles = ({ color, fontSize, fontFamily }) => ({
heading: {
Copy link
Member

Choose a reason for hiding this comment

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

I’d compose using cx() function — would make code simpler and shorter.


import Styled from 'rsg-components/Styled';

import HeadingRenderer from 'rsg-components/Heading/HeadingRenderer';
Copy link
Member

Choose a reason for hiding this comment

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

Should be import HeadingRenderer from 'rsg-components/Heading'*Render components are implementation detail, we should’t leak to the caller code. See for details: https://react-styleguidist.js.org/docs/development.html

import cx from 'classnames';
import Styled from 'rsg-components/Styled';

function HeadingRenderer({ classes, depth, id, deprecated, children }) {
Copy link
Member

Choose a reason for hiding this comment

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

level sounds better than depth for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure can use level. I used depth because that prop name was already in place from the SectionHeadingRenderer, which is where this component was extracted from.

Copy link
Member

Choose a reason for hiding this comment

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

I see ;-) This line is funny:

const headingLevel = Math.min(6, depth);

Let’s make it level everywhere.


function MarkdownHeading({ classes, depth, children }) {
return (
<div className={classes.spacing}>
Copy link
Member

Choose a reason for hiding this comment

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

Maybe Heading component should accept className? And we could get rid of the div here.

<div className={classes.toolbar}>{toolbar}</div>
</Tag>
<HeadingRenderer id={id} depth={depth} deprecated={deprecated}>
<div className={classes.root}>
Copy link
Member

Choose a reason for hiding this comment

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

And get rid or this div as well ;-)

@ryanoglesby08
Copy link
Contributor Author

ryanoglesby08 commented Oct 17, 2017

Thanks for the feedback, will work on incorporating your suggestions.

I will also continue down this path and implement things more cleanly and tested, with the end goal of replacing all the Markdown overrides with replaceable components:

To do:

  • Replace "a" with Link
  • Replace "h1-h6" with Headings
  • Replace "p" with Paragraph
  • Replace "ul, ol, li" with List
  • Replace "blockquote" with Blockquote
  • Replace "hr" with Hr
  • Replace "em" with Em
  • Replace "strong" with Strong
  • Replace "code" with Code
  • Replace "pre" with Pre
  • Replace "table" with Table

@ryanoglesby08
Copy link
Contributor Author

Also, I noticed that the Markdown.js file has styles for "input" elements. Is this necessary? There is no Markdown syntax for inputs, and I'm not sure the purpose of trying to embed inputs in Markdown documentation.

https://github.com/styleguidist/react-styleguidist/blob/master/src/rsg-components/Markdown/Markdown.js#L121-L125

@sapegin
Copy link
Member

sapegin commented Oct 18, 2017

Maybe better to split into two (or more PRs) if that’s convenient for you.

Also, I noticed that the Markdown.js file has styles for "input" elements. Is this necessary?

They are for todos like in your previous comment ;-)

@ryanoglesby08
Copy link
Contributor Author

Cool, will break it up into multiple PRs. Will leave this one here to keep the todo list if you don't mind.

@sapegin
Copy link
Member

sapegin commented Oct 20, 2017

I’d finish this one because it looks very close to done and then continue when you have time.

@quantizor
Copy link
Contributor

@ryanoglesby08 actually GFM task lists will render inputs: https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments

GFM is supported in markdown-to-jsx

@ryanoglesby08
Copy link
Contributor Author

All elements within Markdown now have associated components, making them easy to override consumers. Closing this PR. Thanks for all the suggestions and help @sapegin

@ryanoglesby08 ryanoglesby08 deleted the custom-react-components-for-markdown-components branch March 7, 2018 19:17
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.

None yet

3 participants