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

feat(notifications): new light/dark mode colors #1842

Merged
merged 20 commits into from
Jun 27, 2024

Conversation

geotrev
Copy link
Contributor

@geotrev geotrev commented Jun 18, 2024

Description

Components updated in this PR:

  • Notification
    • Notification.Close
    • Notification.Paragraph
    • Notification.Title
  • Alert
    • Alert.Close
    • Alert.Paragraph
    • Alert.Title
  • Well
    • Well.Paragraph
    • Well.Title
  • GlobalAlert
    • GlobalAlert.Button
    • GlobalAlert.Close
    • GlobalAlert.Content
    • GlobalAlert.Title

Detail

Internal prop spreads have been converted to transient props, with the exception of props used by non-converted components (e.g., GlobalAlert.Button retains all props from its base Button).

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

@geotrev geotrev self-assigned this Jun 18, 2024
@geotrev geotrev requested a review from a team as a code owner June 18, 2024 22:23
switch ($alertType) {
case 'success': {
borderColor = getColor({
variable: 'border.successEmphasis',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interested in thoughts around this use of emphasis vs non-emphasis. In general, I tried to use non-emphasis with foreground and emphasis with background. Does this align with design intent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note this doesn't apply across all components, and at some points foreground is using emphasis (see StyledAlert).

I'd like to ensure that when a consumer updates a color variable, it cascades through these components in the least confusing way.

Also, let me know if I'm overthinking it. 😛

@coveralls
Copy link

Coverage Status

coverage: 96.035% (-0.008%) from 96.043%
when pulling 8991351 on george/notifications-recolor
into 54514f3 on next.

@geotrev geotrev force-pushed the george/notifications-recolor branch from 4b8b9f6 to 00a21ef Compare June 20, 2024 01:40
@coveralls
Copy link

Coverage Status

coverage: 96.035% (-0.008%) from 96.043%
when pulling be05ccb on george/notifications-recolor
into 54514f3 on next.

@coveralls
Copy link

Coverage Status

coverage: 96.035% (-0.008%) from 96.043%
when pulling 1b81444 on george/notifications-recolor
into 54514f3 on next.

@steue
Copy link

steue commented Jun 20, 2024

thanks @geotrev!! for posterity from our IC sync

  1. default well in dark mode should have "default" styling, then "raised" styling when isFloating
image

2. design is in agreement to "fix" button styling so warning button treatment uses yellow-700. looks like you tackled that already!

other than that it looks good!

@coveralls
Copy link

Coverage Status

coverage: 96.035% (-0.008%) from 96.043%
when pulling 6650cf4 on george/notifications-recolor
into 54514f3 on next.

Comment on lines +95 to +96
'data-garden-id': COMPONENT_ID,
'data-garden-version': PACKAGE_VERSION
Copy link
Member

Choose a reason for hiding this comment

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

I know I said all Styled files need retrieveComponentStyles, but I wonder if this particular one is desirable given that it is always meant to be extended. I suppose this doesn't hurt, but is it necessary?

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 remember we had some back and forth originally, and we decided to leave out the details of the base component because we expected all other icon components (like this one) to define the COMPONENT_ID AND retrieveComponentStyles etc.


return (
<StyledClose ref={ref} hue={hue} aria-label={ariaLabel} {...props}>
<StyledClose ref={ref} $type={type} aria-label={ariaLabel} {...props} focusInset size="small">
<XStrokeIcon />
Copy link
Member

Choose a reason for hiding this comment

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

Do we get better results with the 16px? The 12px is looking unintentionally heavy 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.

For comparison:

12px
Screenshot 2024-06-20 at 3 33 56 PM

16px
Screenshot 2024-06-20 at 3 34 06 PM

packages/notifications/src/styled/StyledBase.ts Outdated Show resolved Hide resolved
packages/notifications/src/styled/StyledBase.ts Outdated Show resolved Hide resolved
Comment on lines 25 to 28
const lightDarkOptions = (lightOffset: number, darkOffset: number) => ({
light: { offset: lightOffset },
dark: { offset: darkOffset }
});
Copy link
Member

Choose a reason for hiding this comment

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

I thought the design directive for GlobalAlert was to go with one set of colors, regardless of light/dark mode. Hopefully the color logic below can be simplified.

Copy link
Contributor Author

@geotrev geotrev Jun 20, 2024

Choose a reason for hiding this comment

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

Can you clarify what you are hoping to see / what isn't aligning for you? What are you hoping to see in terms of simplification?

Steph, Lucijan and I had a brief exchange about using variables here instead of the raw colors as the semantic importance of them fits well with GlobalAlert (success, error, warning, etc). For instance, if a consumer updates background.successEmphasis from green to blue, wouldn't we expect GA to reflect the new success color for its success type?

Unless of course I've been misunderstanding the intent of GA this entire time and there is preference to directly reference the colors without variables (in order to ensure the same palette is used regardless of what variables are set). 🤔

Comment on lines 39 to 41
let offsetOptions: OffsetOptions = { light: { offset: 200 }, dark: { offset: 300 } };
let offsetHoverOptions: OffsetOptions = { light: { offset: 300 }, dark: { offset: 400 } };
let offsetActiveOptions: OffsetOptions = { light: { offset: 400 }, dark: { offset: 500 } };
Copy link
Member

Choose a reason for hiding this comment

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

Repeating from the GlobalAlert comment, I don't think we should be seeing light/dark offsets. The GlobalAlert.Button functions the same regardless of mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar to my comment on the other comment, the offsets are there to ensure the underlying shade remains consistent between light/dark. If that isn't going to work here, we should definitely discuss in more detail.

Copy link
Member

Choose a reason for hiding this comment

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

The direction I heard from @lucijanblagonic and @steue is that the components on the surface of a GlobalAlert do not change color (or transition hover/active state) differently in light & dark modes. I'm sure we want to use variables. But I wasn't expecting to see the light and dark parameters in use for getColor here.

Copy link
Contributor Author

@geotrev geotrev Jun 24, 2024

Choose a reason for hiding this comment

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

Oh, I see what you mean. The reason is that the values used in those variables between light and dark already differ, so they need to be offset to meet the consistent shade in either mode. Hopefully I'm understanding correctly.

Comment on lines 74 to 86
light: { offset: 200 },
dark: { offset: 500 },
theme
});
activeBackgroundColor = getColor({
variable: 'background.warningEmphasis',
transparency: theme.opacity[200],
theme
});
activeForegroundColor = getColor({
variable: 'foreground.warningEmphasis',
light: { offset: 300 },
dark: { offset: 600 },
Copy link
Member

Choose a reason for hiding this comment

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

Ditto re: modeless on GlobalAlert.Close.

Comment on lines 50 to 60
light: { offset: -400 },
dark: { offset: -100 },
theme
});
break;
case 'error':
// red/300
color = getColor({
variable: 'foreground.danger',
light: { offset: -400 },
dark: { 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.

Also modeless for the GlobalAlert icon.

Comment on lines 32 to 39
color = getColor({ variable: 'foreground.warningEmphasis', dark: { offset: 600 }, theme });
break;

case 'info':
color = getColorV8('primaryHue', 800, props.theme);
color = getColor({
variable: 'foreground.primary',
light: { offset: 200 },
dark: { offset: 300 },
Copy link
Member

Choose a reason for hiding this comment

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

Ditto re: modeless for GlobalAlert.Title.

Comment on lines 21 to 25
export const validationTypes: Record<Type, string> = {
success: 'success',
error: 'error',
warning: 'warning',
info: 'info'
Copy link
Contributor

Choose a reason for hiding this comment

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

❤️

export type Hue = 'successHue' | 'warningHue' | 'dangerHue' | 'neutralHue';

export const NotificationsContext = createContext<Hue | undefined>(undefined);
export const NotificationsContext = createContext<Type | undefined>(undefined);
Copy link
Contributor

Choose a reason for hiding this comment

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

[nit] The props.type is required, thus should always defined.

To align the context API with the props', should we specify a default rather than using undefined?

Suggested change
export const NotificationsContext = createContext<Type | undefined>(undefined);
export const NotificationsContext = createContext<Type | undefined>('info');

Doing so will make things a bit clearer in that file:

https://github.com/zendeskgarden/react-components/pull/1842/files#diff-30a97b0e497db8834422a4c3a59fd93ac89d538cb7fc5a65d34f0f9be4850c73R17

https://github.com/zendeskgarden/react-components/pull/1842/files#diff-30a97b0e497db8834422a4c3a59fd93ac89d538cb7fc5a65d34f0f9be4850c73R29

Copy link
Contributor Author

@geotrev geotrev Jun 20, 2024

Choose a reason for hiding this comment

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

I think I need to look into this more. I'm suspicious the issue is actually because Alert and Notifications share view subcomponent (Close, Title, etc), but only Alert requires type, so it being undefined might be a valid scenario. I'll check it out.

Copy link
Contributor Author

@geotrev geotrev Jun 21, 2024

Choose a reason for hiding this comment

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

OK, I confirmed that in all places where type is not required (e.g., subcomponents), there are fall backs. The rest of the components seem to handle the required prop appropriately.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for clarifying. 💯

@coveralls
Copy link

Coverage Status

coverage: 96.015% (-0.03%) from 96.043%
when pulling 1be280c on george/notifications-recolor
into 54514f3 on next.

@coveralls
Copy link

Coverage Status

coverage: 96.023% (-0.02%) from 96.043%
when pulling 9244fe1 on george/notifications-recolor
into 54514f3 on next.

Comment on lines 74 to 78
const boxShadow = shadows.lg(offsetY, blurRadius, color);

return css`
border-color: ${borderColor};
box-shadow: ${$isFloating && boxShadow};
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
const boxShadow = shadows.lg(offsetY, blurRadius, color);
return css`
border-color: ${borderColor};
box-shadow: ${$isFloating && boxShadow};
const boxShadow = $isFloating ? shadows.lg(offsetY, blurRadius, color) : undefined;
return css`
border-color: ${borderColor};
box-shadow: ${boxShadow};

[nit] could save an unnecessary function call 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.

Fixed :) ec91f22

Comment on lines 39 to 41
let offsetOptions: OffsetOptions = { light: { offset: 200 }, dark: { offset: 300 } };
let offsetHoverOptions: OffsetOptions = { light: { offset: 300 }, dark: { offset: 400 } };
let offsetActiveOptions: OffsetOptions = { light: { offset: 400 }, dark: { offset: 500 } };
Copy link
Member

Choose a reason for hiding this comment

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

The direction I heard from @lucijanblagonic and @steue is that the components on the surface of a GlobalAlert do not change color (or transition hover/active state) differently in light & dark modes. I'm sure we want to use variables. But I wasn't expecting to see the light and dark parameters in use for getColor here.

@coveralls
Copy link

Coverage Status

coverage: 96.023% (-0.02%) from 96.043%
when pulling ec91f22 on george/notifications-recolor
into 54514f3 on next.

@coveralls
Copy link

Coverage Status

coverage: 96.019% (-0.02%) from 96.043%
when pulling 6b16bab on george/notifications-recolor
into 54514f3 on next.

@geotrev geotrev force-pushed the george/notifications-recolor branch from d56fd54 to 01cffd2 Compare June 25, 2024 21:39
@geotrev geotrev force-pushed the george/notifications-recolor branch from 01cffd2 to 0bcf703 Compare June 25, 2024 21:39
@coveralls
Copy link

Coverage Status

coverage: 96.024% (-0.03%) from 96.057%
when pulling 0bcf703 on george/notifications-recolor
into ee0e4f5 on next.

Comment on lines 36 to 57
if (['error', 'success'].includes($alertType)) {
const borderVariable =
$alertType === 'success' ? 'border.successEmphasis' : 'border.dangerEmphasis';
const backgroundVariable =
$alertType === 'success' ? 'background.successEmphasis' : 'background.dangerEmphasis';
const foregroundVariable =
$alertType === 'success' ? 'foreground.success' : 'foreground.danger';

borderColor = getColor({ variable: borderVariable, light: { offset: 100 }, theme });
backgroundColor = getColor({ variable: backgroundVariable, theme });
foregroundColor = getColor({ variable: foregroundVariable, light: { offset: -600 }, theme });
focusVariable =
$alertType === 'success' ? 'foreground.successEmphasis' : 'foreground.dangerEmphasis';
anchorHoverColor = theme.palette.white;
anchorActiveColor = theme.palette.white;
} else {
const borderVariable =
$alertType === 'warning' ? 'border.warningEmphasis' : 'border.primaryEmphasis';
const backgroundVariable =
$alertType === 'warning' ? 'background.warningEmphasis' : 'background.primaryEmphasis';
const foregroundVariable =
$alertType === 'warning' ? 'foreground.warning' : 'foreground.primary';
Copy link
Member

Choose a reason for hiding this comment

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

Are these ternaries buying us much? Feels like the previous switch was more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted. :)

Comment on lines 59 to 63
borderColor = getColor({ variable: borderVariable, light: { offset: -300 }, theme });
backgroundColor = getColor({ variable: backgroundVariable, light: { offset: -400 }, theme });
foregroundColor = getColor({ variable: foregroundVariable, light: { offset: 100 }, theme });
anchorHoverColor = getColor({ variable: foregroundVariable, light: { offset: 200 }, theme });
anchorActiveColor = getColor({ variable: foregroundVariable, light: { offset: 300 }, theme });
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be better to use the offset: xx parameter throughout rather than light: { offset: xx } as the intent is to adjust theme-agnostic (which we know is now always forced to light).

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

@@ -119,7 +112,7 @@ const sizeStyles = (props: ThemeProps<DefaultTheme>) => {
export const StyledGlobalAlert = styled.div.attrs({
'data-garden-id': COMPONENT_ID,
'data-garden-version': PACKAGE_VERSION
})`
})<IStyledGlobalAlertProps>`
Copy link
Member

Choose a reason for hiding this comment

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

Is this type parameter required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just so the $alertType prop is valid in the elements JSX side.

Comment on lines +40 to +42
let offsetOptions: OffsetOptions;
let offsetHoverOptions: OffsetOptions;
let offsetActiveOptions: OffsetOptions;
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
let offsetOptions: OffsetOptions;
let offsetHoverOptions: OffsetOptions;
let offsetActiveOptions: OffsetOptions;
let offset: number;
let offsetHover: number;
let offsetActive: number;

...again, I think just using the getColor({ theme, offset: <number> }) is the better way to go, and easier to read/maintain.

Comment on lines 33 to 69
if (['success', 'error'].includes($alertType)) {
const variable = $alertType === 'success' ? 'background.success' : 'background.danger';
focusVariable =
$alertType === 'success' ? 'foreground.successEmphasis' : 'foreground.dangerEmphasis';

hoverBackgroundColor = getColor({ variable, theme, transparency: theme.opacity[100] });
hoverForegroundColor = theme.palette.white;
activeBackgroundColor = getColor({ variable, theme, transparency: theme.opacity[200] });
activeForegroundColor = theme.palette.white;
} else if ($alertType === 'warning') {
const bgVariable = 'background.warningEmphasis';
const foregroundVariable = 'foreground.warningEmphasis';
focusVariable = 'foreground.warning';

hoverBackgroundColor = getColor({
variable: bgVariable,
transparency: theme.opacity[100],
theme
});
hoverForegroundColor = getColor({
variable: foregroundVariable,
light: { offset: 200 },
theme
});
activeBackgroundColor = getColor({
variable: bgVariable,
transparency: theme.opacity[200],
theme
});
activeForegroundColor = getColor({
variable: foregroundVariable,
light: { offset: 300 },
theme
});
} else {
focusVariable = 'foreground.primary';
}
Copy link
Member

Choose a reason for hiding this comment

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

ditto re: ternaries .. the previous switch feels more readable/straightforward to process.

Comment on lines 50 to 58
light: { offset: -400 },
theme
});
break;
case 'error':
// red/300
color = getColor({
variable: 'foreground.danger',
light: { offset: -400 },
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
light: { offset: -400 },
theme
});
break;
case 'error':
// red/300
color = getColor({
variable: 'foreground.danger',
light: { offset: -400 },
offset: -400,
theme
});
break;
case 'error':
// red/300
color = getColor({
variable: 'foreground.danger',
offset: -400,

@steue
Copy link

steue commented Jun 27, 2024

thanks for the fixes! visually looks good to me!

@geotrev geotrev requested a review from jzempel June 27, 2024 19:05
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.

🙌

@coveralls
Copy link

Coverage Status

coverage: 96.024% (-0.03%) from 96.057%
when pulling 11836cc on george/notifications-recolor
into ee0e4f5 on next.

Copy link
Contributor

@ze-flo ze-flo left a comment

Choose a reason for hiding this comment

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

So many colors! 🤩 🟥 🟢 🟨 🟦 🌈

@coveralls
Copy link

Coverage Status

coverage: 96.024% (-0.03%) from 96.057%
when pulling 9067ce0 on george/notifications-recolor
into ee0e4f5 on next.

@geotrev geotrev merged commit f5ed1a9 into next Jun 27, 2024
5 checks passed
@geotrev geotrev deleted the george/notifications-recolor branch June 27, 2024 19:59
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.

6 participants