Skip to content

Conversation

ze-flo
Copy link
Contributor

@ze-flo ze-flo commented Jul 17, 2024

Description

Adds dark / light mode support to @zendeskgarden/react-colorpickers

Detail

  • Adds dark / light mode support to ColorPicker, ColorPickerDialog, ColorSwatch, and ColorSwatchDialog
  • Simplify CSS with isOpaque option
  • Use transient props to avoid invalid DOM attributes

Screenshot 2024-07-17 at 7 39 56 AM

Screenshot 2024-07-17 at 7 40 29 AM
Screenshot 2024-07-17 at 7 40 44 AM

Checklist

  • 👌 design updates will be Garden Designer approved (add the designer as a reviewer)
  • 🌐 demo is up-to-date (npm start)
  • ⬅️ renders as expected with reversed (RTL) direction
  • 🤘 renders as expected with Bedrock CSS (?bedrock)
  • 💂‍♂️ includes new unit tests. Maintain existing coverage (always >= 96%)
  • ♿ tested for WCAG 2.1 AA accessibility compliance
  • 📝 tested in Chrome, Firefox, Safari, and Edge

const thumbHoverBorderColor = thumbHoverBackgroundColor;

return `
border-color: ${props.isOpaque && getColorV8('background', 600 /* default shade */, props.theme)};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the isOpaque option, the border was only used for positioning. The border-color must then match with the background color of the the container the ColorPicker with isOpaque renders into. That can be problematic in some cases.

Screenshot 2024-07-17 at 7 21 54 AM

So I refactored the CSS to remove it.

Copy link
Contributor

Choose a reason for hiding this comment

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

If this ends up having no issues with the final interaction/element then sounds good 👍

$green: number;
$blue: number;
$alpha?: number;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🔥

Copy link
Contributor

@geotrev geotrev left a comment

Choose a reason for hiding this comment

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

Looking good!

style: {
backgroundSize: 'auto',
background: background(props)
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, why can't this live in the style block below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this approach avoids dynamically creating a new class every time the color props change. styled-component will warn you when that happens.

Copy link
Member

Choose a reason for hiding this comment

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

...and performance drops through the floor

Copy link
Contributor

Choose a reason for hiding this comment

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

💀

Copy link
Member

@jzempel jzempel left a comment

Choose a reason for hiding this comment

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

[nit] should the data for the ColorSwatch demos be updated to show all 12 colors from the primary (blue, green, red, yellow) palette?

}
${props =>
!props.$isOpaque &&
css`
Copy link
Member

Choose a reason for hiding this comment

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

Is css necessary here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This provides proper placement for the sliders when isOpaque is false.

Copy link
Member

Choose a reason for hiding this comment

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

yep, I get that. More wondering whether this can be a simple template literal rather than invoking the css function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried the template literal first but it didn't parse correctly. I'll give it another shot.

Copy link
Member

Choose a reason for hiding this comment

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

...as I understand it, styled already handles this, making css redundant...

during flattening, styled-components ignores interpolations that evaluate to undefined, null, false, or an empty string ("")

https://styled-components.com/docs/advanced#tagged-template-literals

const colorStyles = (props: IStyledRangeProps & ThemeProps<DefaultTheme>) => {
const thumbBackgroundColor = getColorV8('neutralHue', 100, props.theme);
const colorStyles = ({ theme }: ThemeProps<DefaultTheme>) => {
const thumbBackgroundColor = getColor({ theme, variable: 'background.default' });
Copy link
Member

Choose a reason for hiding this comment

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

@lucijanblagonic maybe just me, but I'm finding these dark mode thumbs very difficult to see. Somehow I don't have the same problem with shadowed white over white background.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1, feels like an accessibility concern for sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@steue @lucijanblagonic For clarity, we're referring to this:

Screenshot 2024-07-17 at 7 40 13 AM

Copy link

Choose a reason for hiding this comment

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

great observation yall! curious about your thoughts of bumping up the contrast by setting the thumbs to bg/raised with a -100 offset? (looks brighter)
image

Copy link
Member

Choose a reason for hiding this comment

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

curious about your thoughts of bumping up the contrast by setting the thumbs to bg/raised with a -100 offset? (looks brighter)

@steue for me, that color tweak works great 🙌

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated. ✅

Screenshot 2024-07-19 at 1 29 57 PM
Screenshot 2024-07-19 at 1 29 44 PM

Comment on lines 42 to 47
export interface IRGBColorProps {
$red: number;
$green: number;
$blue: number;
$alpha?: number;
}
Copy link
Member

Choose a reason for hiding this comment

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

Can this move to a types.ts file within the styled directory? We just wouldn't want to mistake the fact that this interface should never be publicly exported.

Copy link

@steue steue left a comment

Choose a reason for hiding this comment

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

sans the thumb treatment, everything looks good to me! great work!

}

const sizeStyles = (props: IStyledSlidersProps & ThemeProps<DefaultTheme>) => {
if (props.$isOpaque) return undefined;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (props.$isOpaque) return undefined;
if (props.$isOpaque) {
return undefined;
}

Conditions in Garden should always be blocks. We used to lint for this, but the rule was deprecated. Probably need to bring it back with a plugin since prettier doesn't cover us.

@lucijanblagonic
Copy link

The changes here look good, thanks @steue for jumping in. The only thing that seems off is the hover behavior of the handle. I would expect the hover to lighten on hover (in dark mode), to be in line with other interactive controls. What do you think?

@steue
Copy link

steue commented Jul 22, 2024

The changes here look good, thanks @steue for jumping in. The only thing that seems off is the hover behavior of the handle. I would expect the hover to lighten on hover (in dark mode), to be in line with other interactive controls. What do you think?

agreed!

@ze-flo
Copy link
Contributor Author

ze-flo commented Jul 22, 2024

The changes here look good, thanks @steue for jumping in. The only thing that seems off is the hover behavior of the handle. I would expect the hover to lighten on hover (in dark mode), to be in line with other interactive controls. What do you think?

agreed!

Great! In dark mode, the slider's thumb is using background.raised with an offset: -100 for its default state. @steue What offset would you recommend for the hover state?

@geotrev
Copy link
Contributor

geotrev commented Jul 22, 2024

Not sure the best place to put this so I'll throw it here. 😅

I'm going off of the updated designs:

Screenshot 2024-07-22 at 11 51 12 AM Screenshot 2024-07-22 at 12 03 29 PM

I'm still worried about this contrast. Even with the box shadow, the thumb blends in with the background especially at the ends of the range (which is the default state).

I'm not sure what the best approach is (border, or maybe flipping the thumb to be white for dark mode and dark grey for light mode). Maybe this isn't a problem we can solve in this PR, which is also fair. But wanted to at least put it our there for posterity.

I also asked Jen over in accessibility and she agreed, FWIW. She shared the criterion, which specifies:

For active controls any visual information provided that is necessary for a user to identify that a control is present and how to operate it must have a minimum 3:1 contrast ratio with the adjacent colors.

This success criterion does not require that controls have a visual boundary indicating the hit area, but if the visual indicator of the control is the only way to identify the control, then that indicator must have sufficient contrast.

@steue
Copy link

steue commented Jul 22, 2024

What offset would you recommend for the hover state?

i would imagine following our default on hover, so another -100 (effectively -200)?

@steue
Copy link

steue commented Jul 22, 2024

@geotrev valid concern! color pickers have interesting a11y considerations as colors themselves pose inherent issues. we can get into the nitty gritty of it, but where is the contrast compared against? is it against the colors in the slider itself or the BG? you're right, though the the thumb might not always achieve the 3:1 contrast ratio.

that said, the overall design does incorporate alternative methods for controlling color that are accessible. (i.e. thumbs / sliders controllable via keyboard and input fields to control HSL/RGB etc) i do think we could explore treatment as another treatment

@ze-flo
Copy link
Contributor Author

ze-flo commented Jul 22, 2024

What offset would you recommend for the hover state?

i would imagine following our default on hover, so another -100 (effectively -200)?

Following @lucijanblagonic 's comment:

I would expect the hover to lighten on hover (in dark mode)

@steue If the default state is background.raised with an offset: -100, should we increase the offset by 100 (essentially just background.raised) for hover instead?

@geotrev
Copy link
Contributor

geotrev commented Jul 22, 2024

@geotrev valid concern! color pickers have interesting a11y considerations as colors themselves pose inherent issues. we can get into the nitty gritty of it, but where is the contrast compared against? is it against the colors in the slider itself or the BG? you're right, though the the thumb might not always achieve the 3:1 contrast ratio.

@steue The contrast is with everything behind it, but primarily the dark grey background. Currently the background and the thumb have less than a 2:1 contrast ratio, which is concerning in the cases I mentioned. Especially since we can't depend on the thumb being positioned inside the slider at all times.

The issue of the contrast not always being perfect could be a good reason to use a border. A single solid color will present persistence issues like you mention.

that said, the overall design does incorporate alternative methods for controlling color that are accessible. (i.e. thumbs / sliders controllable via keyboard and input fields to control HSL/RGB etc) i do think we could explore treatment as another treatment

That is true. There are input fields as well. I bring it up as a medium-high concern mainly because the bulk of the picker UI contains visual/color-based controls.

@lucijanblagonic
Copy link

I don't think there is a difference in light or dark mode when it comes to accessibility in this case. Having a thumb in the color where it blends with the background shares the same challenge in light and dark. Here is an example with the thumb changes in the slider and in the color well.

  • Thumb in color well has a white 2px inner border and 1px outer black border.
  • Thumb in the slider has background/default and then border/input applied. That way the stroke helps to distinguish the handle a bit.

image

@geotrev
Copy link
Contributor

geotrev commented Jul 23, 2024

That makes sense and would definitely remediate the concerns. Not a blocker for this PR of course, we can set aside time to do it after if preferred

@ze-flo
Copy link
Contributor Author

ze-flo commented Jul 24, 2024

@lucijanblagonic @steue The latest preview increases the thumbs contrast based on the last suggestion. The border treatment of the range thumbs matches with the inputs' below.

Screenshot 2024-07-23 at 4 34 56 PM
Screenshot 2024-07-23 at 4 34 34 PM

I think this looks good. Hope this works for all too! 🤞

Comment on lines +68 to +73
const thumbBorderColor = getColor({
theme,
variable: 'border.default',
dark: { offset: -100 },
light: { offset: 100 }
});
Copy link
Member

Choose a reason for hiding this comment

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

[nit] now that the thumbs have a visible border, can we check that the transition animation is updated to include the border?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Transition animations appear to be inherited from Range:

transition:
border-color .25s ease-in-out,
background-color .25s ease-in-out;

Screenshot 2024-07-24 at 6 31 22 AM

Copy link
Member

Choose a reason for hiding this comment

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

Ok, my bad. I wasn't viewing the :hover state.

Copy link

@lucijanblagonic lucijanblagonic left a comment

Choose a reason for hiding this comment

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

Tested and looks good, feel free to merge after resolving @jzempel 's comment for transition.

@ze-flo ze-flo merged commit bc7b6b1 into next Jul 24, 2024
@ze-flo ze-flo deleted the ze-flo/color-pickers-recolor branch July 24, 2024 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

5 participants