forked from migtools/lib-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add LabelCustomColor component (migtools#125)
* Initial implementation Signed-off-by: Mike Turley <[email protected]> * All in on tinycolor2 instead of linear-gradient Signed-off-by: Mike Turley <[email protected]> * Tuning brightness Signed-off-by: Mike Turley <[email protected]> * Remove @types/react-color because it does something weird to the built-in ReactNode type Signed-off-by: Mike Turley <[email protected]> * Tuning brightness Signed-off-by: Mike Turley <[email protected]> * Tuning brightness some more Signed-off-by: Mike Turley <[email protected]> * Properly export Signed-off-by: Mike Turley <[email protected]> * Handle extra props, add examples from Tackle Signed-off-by: Mike Turley <[email protected]> * Update docs paragraph Signed-off-by: Mike Turley <[email protected]> * Better margins in second example Signed-off-by: Mike Turley <[email protected]> * Use the readability functions in tinycolor2 Signed-off-by: Mike Turley <[email protected]> * Nits Signed-off-by: Mike Turley <[email protected]> * Cleanup Signed-off-by: Mike Turley <[email protected]> * Introduce a cache, perf test example, and better description Signed-off-by: Mike Turley <[email protected]> * More notes for the doc Signed-off-by: Mike Turley <[email protected]> * Fix WCAG URL Signed-off-by: Mike Turley <[email protected]> --------- Signed-off-by: Mike Turley <[email protected]>
- Loading branch information
Showing
7 changed files
with
2,222 additions
and
1,967 deletions.
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); | ||
} | ||
// 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.