Conversation
|
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/primer/primer-components/ov9e9os1w |
🤔 Can we do both? const fontSizes = [...]
Object.assign(fontSizes, {
name: value,
another: value
}) |
|
@BinaryMuse oooo good idea duh 😂 |
| declare module '@primer/components/src/Position' { | ||
| import {Relative, Absolute, Sticky, Fixed} from '@primer/components' | ||
| export {Relative, Absolute, Sticky, Fixed} | ||
| } |
There was a problem hiding this comment.
@dmarcey do these modules look right? previously we were exporting each one from @primer/components/src/Relative, etc but that's incorrect because there's not actually a file there (they are all exported from on Position file) similar to how we do it for Heading
There was a problem hiding this comment.
NB: It’s possible to combine the import and export into a single line:
export { Relative, Absolute, Sticky, Fixed } from "@primer/components";
There was a problem hiding this comment.
That looks like it should work! @smockle 's suggestion seems like it simplifies things a little bit too.
| } | ||
| // | ||
|
|
||
| const HeadingInternal = styled.h2` |
There was a problem hiding this comment.
This is basically the same as Heading but without a default font size. All of the stuff above this line will get removed when we deprecate Heading
src/utils/Deprecated.js
Outdated
| const Deprecated = ({componentName, message, children}) => { | ||
| console.warn(`WARNING! ${componentName} will be deprecated soon. ${message}`) | ||
| return children | ||
| } | ||
|
|
There was a problem hiding this comment.
I really really like this! Thoughts about adding a since prop that specifies the version that the deprecation was created in? Could also be useful for us to grep through the codebase and see which deprecations are ready to be removed.
There was a problem hiding this comment.
yeah that's a great idea! I'll add it!
There was a problem hiding this comment.
I added a version prop instead, for which version the component is planning to be deprecated in. I'm assuming the term deprecated to mean completely removed so this is what I was thinking the process would be:
- When you are getting ready to remove a component or prop, first wrap the component in
Deprecatedand specify which future version the component will be completely removed in.
If there is a migration strategy (in this case it's to use H1, etc instead), that new API should be available when the deprecation notice is added so the users can start migrating immediately. In other words, in most cases when you are adding a new component or prop that replaces an old component/prop, keep both around for a period of time to allow folks to migrate. It might not always make sense to do this. I could see situations where we want to remove a component completely without a replacement or with a replacement that lives outside the library (for instance, removing StyledOcticon in favor of the external @primer/styled-octicons library).
-
Keep the deprecation warning + old component around for a specified period of time. In this case, since we're going to ship 19.0.0 very soon, I set it for 20.0.0 so that we can give folks time to see the warning.
-
When shipping a major release, search the codebase for
version=<VERSION ABOUT TO BE RELEASED>. Completely remove the components wrapped inDeprecatedand all related type definitions, exports, docs, tests etc.
What do you think? Maybe the component name should be DeprecationWarning instead?
There was a problem hiding this comment.
I think "deprecated" is commonly used as "still available but in the process of being changed or removed;" if an API is completely removed, it's no longer deprecated.
That said, I'm okay with using a prop to note which version we plan on removing the feature in. I guess it's not all that important to know when the API was deprecated. The only downside is that time between major releases is not always consistent.
👍 on DeprectionWarning as a name
BinaryMuse
left a comment
There was a problem hiding this comment.
Liking the direction you went with this. A few comments below.
| function withHeading(level) { | ||
| const WithHeading = props => ( | ||
| <HeadingInternal | ||
| as={level} |
There was a problem hiding this comment.
Curious how this behaves if someone does <H1 as={SomeStyledComponent} ...
There was a problem hiding this comment.
Good point 🤔 Since it's such a simple component I'm not sure if it's worth the pain to allow people to pass in a styled component or anything else to the as prop. If folks really need to add some styles to the headings, they could do:
const CustomHeading = styled(H1)`
// custom styles
`
I think allowing the as prop on this component would open it up for folks to change the heading level to to get a different font size like so:
<H1 as='h2'>Heading</H1>
which we want to discourage in favor of this (to encourage proper semantics/a11y:
<H2 fontSize='headingSizes.h1' />
People could even go as far as:
<H1 as='p'>HEADING!</H1>
which we really wouldn't want.
There was a problem hiding this comment.
That sounds good to me, although the TypeScript and propTypes will still list as as a valid prop
| export const H1 = withHeading('h1') | ||
| export const H2 = withHeading('h2') | ||
| export const H3 = withHeading('h3') | ||
| export const H4 = withHeading('h4') | ||
| export const H5 = withHeading('h5') | ||
| export const H6 = withHeading('h6') |
There was a problem hiding this comment.
If Heading is being deprecated then it should probably still be exported as the default export so that the imports don't break. The TS module will need to be updated accordingly.
There was a problem hiding this comment.
Does it matter though since we're exporting everything as named exports in index.js? We aren't importing Heading in any other component files so we shouldn't be relying on the default export anywhere
There was a problem hiding this comment.
The previous module definition for src/Heading was:
declare module '@primer/components/src/Heading' {
import {Heading} from '@primer/components'
export default Heading
}so if we change Heading.js so that Heading isn't being exported as default, that's a breaking change for this TypeScript module.
There was a problem hiding this comment.
Also #789 will make individual modules (JS) requireable, so we will need to stick to an export contract for those.
Co-Authored-By: Michelle Tilley <binarymuse@github.com>
| import {Heading} from '@primer/components' | ||
| export default Heading | ||
| import {Heading, H1, H2, H3, H4, H5, H6} from '@primer/components' | ||
| export {Heading, H1, H2, H3, H4, H5, H6} |
There was a problem hiding this comment.
Can you do
export default Heading;
export {Heading, H1, H2, H3, H4, H5, H6}
for TS compat with the deprecated 'Heading` default export?
|
Closing for now |
This PR implements a new Heading API proposal that I'd love to get some feedback on!
The Problem
Currently in Primer Components, we don't really set font size defaults for different heading sizes. The default
h2gets a heading size set, burt if you change the heading toh3the font size remains the same unless you update it yourself manually using thefontSizeprop. In order for the Heading component to be a useful design system tool, I think it should provide some font size defaults for different heading levels.The Solution
Create separate components for each heading level.
H1,H2,H3,H4,H5, andH6. This nudges the user to think a little more about what heading level they're using, and allows us to set default font sizes (and font sizes for responsive breakpoints!) for each level.Drawbacks
This is obviously a large breaking change because we'd be deprecating
Heading. I considered keepingHeadingand using theasprop but it was finicky (see next section for more details). IMO, having a different component for each heading size feels like the best API but we have been making a lot of breaking changes lately so not 1000000% sure it's worth it.Other Approaches Considered
I considered keeping
Headingand using theasprop to dynamically set the font size. This worked okay but it was fragile and would break if someone were to pass in a styled component to theasprop.This is basically what I tried:
It just didn't feel great and also would have meant we'd need to add a media query in for the mobile font sizes.
Deprecating Heading
I propose that we deprecate the
Headingcomponent gradually in favor of usingH1, H2, H3, H4, H5, H6. I'll keep it in for now + add a deprecation notice, but let's remove it after a month or two ☮️I added a
Deprecatedcomponent that will allow you to throw a console warning whenever a component that it wraps is used.Notes
I wanted to add ajk i figured it out thanks 2 @BinaryMuseheadingSizesandmobileHeadingSizesto the theme and pull from those values so that they could be overridden if needed, but styled system expects to pull from thefontSizesobject in the value for thefontSizeprop, and it would be a huuuuge breaking change to add named keys to thefontSizetheme object (bc it's used in so many places), so I ended up just hard coding these values. If we decide to update the heading font sizes in the future it will be easy enough to update in this one component, and if someone would like to use a different heading size scale, they can create their own heading components. I think this makes the most sense since the Heading component is basically just setting the correct font size for each heading level anyways.