-
Notifications
You must be signed in to change notification settings - Fork 9
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
feat: Add LabelCustomColor component #125
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
ae0189a
Initial implementation
mturley 6088bf8
All in on tinycolor2 instead of linear-gradient
mturley 8c49012
Tuning brightness
mturley 48663df
Remove @types/react-color because it does something weird to the buil…
mturley 1eedb58
Tuning brightness
mturley 8362f5b
Tuning brightness some more
mturley 7a756e4
Properly export
mturley ef9a871
Handle extra props, add examples from Tackle
mturley 3aad431
Update docs paragraph
mturley 68f7750
Better margins in second example
mturley 97bef6f
Use the readability functions in tinycolor2
mturley ea3ddfb
Nits
mturley 7337518
Cleanup
mturley 1e809db
Introduce a cache, perf test example, and better description
mturley bb5f901
More notes for the doc
mturley ff0977c
Fix WCAG URL
mturley File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
src/components/LabelCustomColor/LabelCustomColor.stories.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs/blocks'; | ||
import { LabelCustomColor } from './LabelCustomColor'; | ||
import { | ||
LabelCustomColorPicker, | ||
LabelCustomColorExamples, | ||
LabelCustomColorPerfTest, | ||
} from './LabelCustomColor.stories.tsx'; | ||
import GithubLink from '../../../.storybook/helpers/GithubLink'; | ||
|
||
<Meta title="Components/LabelCustomColor" component={LabelCustomColor} /> | ||
|
||
# LabelCustomColor | ||
|
||
A wrapper for PatternFly's <a href="https://www.patternfly.org/v4/components/label">Label</a> component that supports | ||
arbitrary custom CSS colors (e.g. hexadecimal) and ensures text will always be readable. | ||
|
||
Applying an arbitrary color to a label presents the possibility of unreadable text due to insufficient color contrast. | ||
This component solves the issue by applying the given color as a border color and using the | ||
[tinycolor2](https://www.npmjs.com/package/tinycolor2) library to determine a lightened background color and darkened | ||
text color (if necessary) in order to reach a color contrast ratio of at least 7:1. This ratio meets the "level AAA" | ||
requirement of the [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/WAI/WCAG21/Understanding/contrast-enhanced). | ||
|
||
**Note: This adjustment means that multiple labels with very similar colors (especially dark colors) may be adjusted to look almost identical.** | ||
|
||
All props of PatternFly's Label component are supported except the `variant` prop (only the default "filled" variant is supported). | ||
|
||
## Examples | ||
|
||
### Arbitrary Color Picker | ||
|
||
Choose any color here to see how the readability adjustments apply to it. | ||
|
||
<Canvas> | ||
<Story story={LabelCustomColorPicker} /> | ||
</Canvas> | ||
|
||
### Color Examples | ||
|
||
<Canvas> | ||
<Story story={LabelCustomColorExamples} /> | ||
</Canvas> | ||
|
||
### Performance Test | ||
|
||
The component maintains a global cache of the readability adjustments it makes for each color. | ||
If labels of the same color are rendered multiple times on a page, each color only needs to be processed once. | ||
|
||
<Canvas> | ||
<Story story={LabelCustomColorPerfTest} /> | ||
</Canvas> | ||
|
||
## Props | ||
|
||
<ArgsTable of={LabelCustomColor} /> | ||
|
||
<GithubLink path="src/components/LabelCustomColor/LabelCustomColor.tsx" /> |
82 changes: 82 additions & 0 deletions
82
src/components/LabelCustomColor/LabelCustomColor.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import * as React from 'react'; | ||
import { SketchPicker } from 'react-color'; | ||
import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; | ||
import { LabelCustomColor } from './LabelCustomColor'; | ||
|
||
export const LabelCustomColorPicker: React.FC = () => { | ||
const [color, setColor] = React.useState('#4A90E2'); | ||
return ( | ||
<> | ||
<LabelCustomColor color={color}>Label Text Here</LabelCustomColor> | ||
<br /> | ||
<br /> | ||
<SketchPicker color={color} onChangeComplete={(newColor) => setColor(newColor.hex)} /> | ||
</> | ||
); | ||
}; | ||
|
||
// Colors from https://github.com/konveyor/tackle2-hub/blob/main/migration/v3/seed/main.go#L331-L766 | ||
const EXAMPLE_COLORS = [ | ||
'#773CF3', | ||
'#74F33C', | ||
'#F33CA9', | ||
'#3CF342', | ||
'#4EF33C', | ||
'#F33CE6', | ||
'#F3AC3C', | ||
'#3CF367', | ||
'#F3D23C', | ||
'#B43CF3', | ||
'#F3493C', | ||
'#3C65F3', | ||
'#3CF3E1', | ||
'#3CF3A4', | ||
'#F33C47', | ||
'#F36F3C', | ||
'#B1F33C', | ||
'#F3E93C', | ||
'#3C7CF3', | ||
'#3C3FF3', | ||
'#3CDFF3', | ||
'#F33C6C', | ||
'#D93CF3', | ||
'#3CF37F', | ||
'#3CF3CA', | ||
'#F33CCF', | ||
'#9AF33C', | ||
'#F3953C', | ||
'#D7F33C', | ||
'#3CA2F3', | ||
'#9C3CF3', | ||
]; | ||
|
||
export const LabelCustomColorExamples: React.FC = () => ( | ||
<> | ||
{EXAMPLE_COLORS.map((color) => ( | ||
<LabelCustomColor key={color} color={color} className={spacing.mXs}> | ||
{color} | ||
</LabelCustomColor> | ||
))} | ||
</> | ||
); | ||
|
||
export const LabelCustomColorPerfTest: React.FC = () => ( | ||
<> | ||
{[ | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
...EXAMPLE_COLORS, | ||
].map((color, index) => ( | ||
<LabelCustomColor key={`${index}-${color}`} color={color} className={spacing.mXs}> | ||
{color} | ||
</LabelCustomColor> | ||
))} | ||
</> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import * as React from 'react'; | ||
import { Label, LabelProps } from '@patternfly/react-core'; | ||
import tinycolor from 'tinycolor2'; | ||
|
||
// Omit the variant prop, we won't support the outline variant | ||
export interface ILabelCustomColorProps extends Omit<LabelProps, 'variant' | 'color'> { | ||
color: string; | ||
} | ||
|
||
const globalColorCache: Record< | ||
string, | ||
{ borderColor: string; backgroundColor: string; textColor: string } | ||
> = {}; | ||
|
||
export const LabelCustomColor: React.FC<ILabelCustomColorProps> = ({ color, ...props }) => { | ||
const { borderColor, backgroundColor, textColor } = React.useMemo(() => { | ||
if (globalColorCache[color]) return globalColorCache[color]; | ||
// Lighten the background 25%, and lighten it further if necessary until it can support readable text | ||
const bgColorObj = tinycolor(color).lighten(25); | ||
const blackTextReadability = () => tinycolor.readability(bgColorObj, '#000000'); | ||
const whiteTextReadability = () => tinycolor.readability(bgColorObj, '#FFFFFF'); | ||
while (blackTextReadability() < 9 && whiteTextReadability() < 9) { | ||
bgColorObj.lighten(5); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice |
||
} | ||
// Darken or lighten the text color until it is sufficiently readable | ||
const textColorObj = tinycolor(color); | ||
while (tinycolor.readability(bgColorObj, textColorObj) < 7) { | ||
if (blackTextReadability() > whiteTextReadability()) { | ||
textColorObj.darken(5); | ||
} else { | ||
textColorObj.lighten(5); | ||
} | ||
} | ||
globalColorCache[color] = { | ||
borderColor: color, | ||
backgroundColor: bgColorObj.toString(), | ||
textColor: textColorObj.toString(), | ||
}; | ||
return globalColorCache[color]; | ||
}, [color]); | ||
return ( | ||
<Label | ||
style={ | ||
{ | ||
'--pf-c-label__content--before--BorderColor': borderColor, | ||
'--pf-c-label__content--link--hover--before--BorderColor': borderColor, | ||
'--pf-c-label__content--link--focus--before--BorderColor': borderColor, | ||
'--pf-c-label--BackgroundColor': backgroundColor, | ||
'--pf-c-label__icon--Color': textColor, | ||
'--pf-c-label__content--Color': textColor, | ||
} as React.CSSProperties | ||
} | ||
{...props} | ||
/> | ||
); | ||
}; | ||
|
||
/* | ||
|
||
Note: if we were to support the outline variant of Label, | ||
we would need to account for the following additional CSS variables: | ||
|
||
--pf-c-label--m-outline__content--Color | ||
--pf-c-label--m-outline__content--before--BorderColor | ||
--pf-c-label--m-outline__content--link--hover--before--BorderColor | ||
--pf-c-label--m-outline__content--link--focus--before--BorderColor | ||
--pf-c-label--m-editable__content--before--BorderColor | ||
--pf-c-label--m-editable__content--hover--before--BorderColor | ||
--pf-c-label--m-editable__content--focus--before--BorderColor | ||
|
||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './LabelCustomColor'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍