From 97adefd1746f1861f74d33ecb0eb6820d2248262 Mon Sep 17 00:00:00 2001 From: Jonathan Zempel Date: Wed, 24 Apr 2024 15:47:53 -0400 Subject: [PATCH 1/3] feat(theming): add system `opacity` values to the theme --- packages/theming/demo/stories/GetColorStory.tsx | 4 +++- packages/theming/demo/utilities.stories.mdx | 2 +- .../theme/__snapshots__/index.spec.ts.snap | 14 ++++++++++++++ packages/theming/src/elements/theme/index.ts | 16 ++++++++++++++++ packages/theming/src/types/index.ts | 1 + packages/theming/src/utils/getColor.ts | 14 +++++++++++--- 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/packages/theming/demo/stories/GetColorStory.tsx b/packages/theming/demo/stories/GetColorStory.tsx index e2f0a548af3..4824d17541f 100644 --- a/packages/theming/demo/stories/GetColorStory.tsx +++ b/packages/theming/demo/stories/GetColorStory.tsx @@ -42,7 +42,7 @@ const Color = ({ dark, hue, light, offset, shade, theme, transparency, variable offset, shade, theme, - transparency: transparency ? transparency / 100 : undefined, + transparency, variable }); @@ -71,6 +71,7 @@ const Color = ({ dark, hue, light, offset, shade, theme, transparency, variable interface IArgs extends Omit { theme: { colors: Omit; + opacity: IGardenTheme['opacity']; palette: IGardenTheme['palette']; }; } @@ -89,6 +90,7 @@ export const GetColorStory: StoryFn = ({ const theme = { ...parentTheme, colors: { ..._theme.colors, base: parentTheme.colors.base }, + opacity: _theme.opacity, palette: _theme.palette }; diff --git a/packages/theming/demo/utilities.stories.mdx b/packages/theming/demo/utilities.stories.mdx index 9ad7d9062d1..18dba9835e3 100644 --- a/packages/theming/demo/utilities.stories.mdx +++ b/packages/theming/demo/utilities.stories.mdx @@ -77,7 +77,7 @@ import README from '../README.md'; light: { control: { type: 'object' } }, offset: { control: { type: 'number' } }, shade: { control: { type: 'number' } }, - transparency: { control: { type: 'range', min: 1 } }, + transparency: { control: { type: 'range', min: 100, max: 1200, step: 100 } }, variable: { control: { type: 'text' } } }} > diff --git a/packages/theming/src/elements/theme/__snapshots__/index.spec.ts.snap b/packages/theming/src/elements/theme/__snapshots__/index.spec.ts.snap index 0ded8bff5be..0f79e8e86ba 100644 --- a/packages/theming/src/elements/theme/__snapshots__/index.spec.ts.snap +++ b/packages/theming/src/elements/theme/__snapshots__/index.spec.ts.snap @@ -155,6 +155,20 @@ exports[`DEFAULT_THEME matches snapshot 1`] = ` "xxl": "32px", "xxxl": "44px", }, + "opacity": { + "100": 0.08, + "1000": 0.8, + "1100": 0.88, + "1200": 0.96, + "200": 0.16, + "300": 0.24, + "400": 0.32, + "500": 0.4, + "600": 0.48, + "700": 0.56, + "800": 0.64, + "900": 0.72, + }, "palette": { "azure": { "100": "#eff7fe", diff --git a/packages/theming/src/elements/theme/index.ts b/packages/theming/src/elements/theme/index.ts index b2f1ffbedbd..76fc45f007b 100644 --- a/packages/theming/src/elements/theme/index.ts +++ b/packages/theming/src/elements/theme/index.ts @@ -191,6 +191,21 @@ const lineHeights = { xxxl: `${BASE * 11}px` }; +const opacity = { + 100: 0.08, + 200: 0.16, + 300: 0.24, + 400: 0.32, + 500: 0.4, + 600: 0.48, + 700: 0.56, + 800: 0.64, + 900: 0.72, + 1000: 0.8, + 1100: 0.88, + 1200: 0.96 +}; + const palette = { ...PALETTE }; /* Exclude product palette from the theme */ @@ -237,6 +252,7 @@ const DEFAULT_THEME: IGardenTheme = { fontWeights, iconSizes, lineHeights, + opacity, palette, rtl: false, shadowWidths, diff --git a/packages/theming/src/types/index.ts b/packages/theming/src/types/index.ts index 3ea95021730..b408599d16d 100644 --- a/packages/theming/src/types/index.ts +++ b/packages/theming/src/types/index.ts @@ -177,6 +177,7 @@ export interface IGardenTheme { xxl: string; xxxl: string; }; + opacity: Record; palette: Record; shadowWidths: { xs: string; diff --git a/packages/theming/src/utils/getColor.ts b/packages/theming/src/utils/getColor.ts index 87bdcf1c3a0..303d0607067 100644 --- a/packages/theming/src/utils/getColor.ts +++ b/packages/theming/src/utils/getColor.ts @@ -71,6 +71,7 @@ const toHex = ( const toColor = ( colors: Omit, palette: IGardenTheme['palette'], + opacity: IGardenTheme['opacity'], scheme: 'dark' | 'light', hue: string, shade?: number | string, @@ -109,7 +110,9 @@ const toColor = ( } if (retVal && transparency) { - retVal = rgba(retVal, transparency); + const alpha = transparency > 1 ? opacity[transparency] : transparency; + + retVal = rgba(retVal, alpha); } return retVal; @@ -147,7 +150,7 @@ const toProperty = (object: object, path: string) => { * - `'chromeHue'` = `theme.colors.chromeHue` * @param {number} [options.shade] A hue shade * @param {number} [options.offset] A positive or negative value to adjust the shade - * @param {number} [options.transparency] An alpha-channel value between 0 and 1 + * @param {number} [options.transparency] A `theme.opacity` key or an alpha-channel value between 0 and 1 */ export const getColor = memoize( ({ dark, hue, light, offset, shade, theme, transparency, variable }: ColorParameters) => { @@ -184,7 +187,12 @@ export const getColor = memoize( } if (_hue) { - retVal = toColor(colors, palette, scheme, _hue, _shade, _offset, _transparency); + const opacity = + theme.opacity && Object.keys(theme.opacity).length > 0 + ? theme.opacity + : DEFAULT_THEME.opacity; + + retVal = toColor(colors, palette, opacity, scheme, _hue, _shade, _offset, _transparency); } if (retVal === undefined) { From 55deea8f4657de8c403ba42e43cd4ea114f747e2 Mon Sep 17 00:00:00 2001 From: Jonathan Zempel Date: Wed, 24 Apr 2024 16:02:12 -0400 Subject: [PATCH 2/3] Add unit test --- .github/PULL_REQUEST_TEMPLATE.md | 1 + packages/theming/src/utils/getColor.spec.ts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 80c4983b42b..cd7a21ca0dd 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,6 +25,7 @@ - [ ] :ok_hand: design updates will be Garden Designer approved (add the designer as a reviewer) - [ ] :globe_with_meridians: demo is up-to-date (`npm start`) - [ ] :arrow_left: renders as expected with reversed (RTL) direction +- [ ] :black_circle: renders as expected in dark mode - [ ] :metal: renders as expected with Bedrock CSS (`?bedrock`) - [ ] :guardsman: includes new unit tests. Maintain existing coverage (always >= 96%) - [ ] :wheelchair: tested for WCAG 2.1 AA accessibility compliance diff --git a/packages/theming/src/utils/getColor.spec.ts b/packages/theming/src/utils/getColor.spec.ts index 3f89549509f..58272fa85c6 100644 --- a/packages/theming/src/utils/getColor.spec.ts +++ b/packages/theming/src/utils/getColor.spec.ts @@ -197,6 +197,15 @@ describe('getColor', () => { expect(color).toBe(expected); }); + it('applies transparency via theme `opacity` as expected', () => { + const hue = 'blue'; + const transparency = 1000; + const color = getColor({ theme: DEFAULT_THEME, hue, transparency }); + const expected = rgba(PALETTE[hue][700], DEFAULT_THEME.opacity[1000]); + + expect(color).toBe(expected); + }); + it('applies mode transparency as expected', () => { const hue = 'blue'; const transparency = 0.5; From 700f17b9888a7317b0076a139c5fc366128d0610 Mon Sep 17 00:00:00 2001 From: Jonathan Zempel Date: Thu, 25 Apr 2024 07:02:19 -0400 Subject: [PATCH 3/3] Handle invalid opacity --- packages/theming/src/utils/getColor.spec.ts | 8 ++++++++ packages/theming/src/utils/getColor.ts | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/packages/theming/src/utils/getColor.spec.ts b/packages/theming/src/utils/getColor.spec.ts index 58272fa85c6..9912521b30f 100644 --- a/packages/theming/src/utils/getColor.spec.ts +++ b/packages/theming/src/utils/getColor.spec.ts @@ -354,5 +354,13 @@ describe('getColor', () => { it('throws an error if shade is invalid', () => { expect(() => getColor({ theme: DEFAULT_THEME, hue: 'blue', shade: NaN })).toThrow(TypeError); }); + + it('throws an error if transparency is invalid', () => { + const invalid = DEFAULT_THEME.opacity[100] + 1; + + expect(() => getColor({ theme: DEFAULT_THEME, hue: 'blue', transparency: invalid })).toThrow( + Error + ); + }); }); }); diff --git a/packages/theming/src/utils/getColor.ts b/packages/theming/src/utils/getColor.ts index 303d0607067..a776fd0a226 100644 --- a/packages/theming/src/utils/getColor.ts +++ b/packages/theming/src/utils/getColor.ts @@ -112,6 +112,10 @@ const toColor = ( if (retVal && transparency) { const alpha = transparency > 1 ? opacity[transparency] : transparency; + if (alpha === undefined) { + throw new Error('Error: invalid `transparency` parameter'); + } + retVal = rgba(retVal, alpha); }