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

Components: Try color theming #44668

Merged
merged 18 commits into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,12 @@
"markdown_source": "../packages/components/src/textarea-control/README.md",
"parent": "components"
},
{
"title": "Theme",
"slug": "theme",
"markdown_source": "../packages/components/src/theme/README.md",
"parent": "components"
},
{
"title": "ToggleControl",
"slug": "toggle-control",
Expand Down
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
- `FontSizePicker`: Convert to TypeScript ([#44449](https://github.com/WordPress/gutenberg/pull/44449)).
- `FontSizePicker`: Replace SCSS with Emotion + components ([#44483](https://github.com/WordPress/gutenberg/pull/44483)).

### Experimental

- Add experimental `Theme` component ([#44668](https://github.com/WordPress/gutenberg/pull/44668)).

## 21.1.0 (2022-09-21)

### Deprecations
Expand Down
20 changes: 20 additions & 0 deletions packages/components/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,26 @@ All new component should be styled using [Emotion](https://emotion.sh/docs/intro

Note: Instead of using Emotion's standard `cx` function, the custom [`useCx` hook](/packages/components/src/utils/hooks/use-cx.ts) should be used instead.

### Themeing

_Note: Themeing is an experimental feature and still being actively developed. Its APIs are an early implementation subject to drastic and breaking changes_

The [`Theme` component](/packages/components/src/theme/README.md) can be used to tweak the visual appearance of the components from the `@wordpress/components` package.

```jsx
import { __experimentalTheme as Theme } from '@wordpress/components';

const Example = () => {
return (
<Theme accent="red">
<Button variant="primary">I'm red</Button>
<Theme accent="blue">
<Button variant="primary">I'm blue</Button>
</Theme>
</Theme>
);
};
```

### Deprecating styles

Expand Down
50 changes: 25 additions & 25 deletions packages/components/src/button/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

&[aria-expanded="true"],
&:hover {
color: var(--wp-admin-theme-color);
color: $components-color-accent;
}

// Unset some hovers, instead of adding :not specificity.
Expand All @@ -31,7 +31,7 @@
// Focus.
// See https://github.com/WordPress/gutenberg/issues/13267 for more context on these selectors.
&:focus:not(:disabled) {
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;

// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 3px solid transparent;
Expand All @@ -43,7 +43,7 @@

&.is-primary {
white-space: nowrap;
background: var(--wp-admin-theme-color);
background: $components-color-accent;
color: $white;
text-decoration: none;
text-shadow: none;
Expand All @@ -52,18 +52,18 @@
outline: 1px solid transparent;

&:hover:not(:disabled) {
background: var(--wp-admin-theme-color-darker-10);
background: $components-color-accent-darker-10;
color: $white;
}

&:active:not(:disabled) {
background: var(--wp-admin-theme-color-darker-20);
border-color: var(--wp-admin-theme-color-darker-20);
background: $components-color-accent-darker-20;
border-color: $components-color-accent-darker-20;
color: $white;
}

&:focus:not(:disabled) {
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
}

&:disabled,
Expand All @@ -72,15 +72,15 @@
&[aria-disabled="true"]:enabled, // This catches a situation where a Button is aria-disabled, but not disabled.
&[aria-disabled="true"]:active:enabled {
color: rgba($white, 0.4);
background: var(--wp-admin-theme-color);
border-color: var(--wp-admin-theme-color);
background: $components-color-accent;
border-color: $components-color-accent;
opacity: 1;
outline: none;

&:focus:enabled {
box-shadow:
0 0 0 $border-width $white,
0 0 0 3px var(--wp-admin-theme-color);
0 0 0 3px $components-color-accent;
}
}

Expand All @@ -93,13 +93,13 @@
/* stylelint-disable */
background-image: linear-gradient(
-45deg,
var(--wp-admin-theme-color) 33%,
var(--wp-admin-theme-color-darker-20) 33%,
var(--wp-admin-theme-color-darker-20) 70%,
var(--wp-admin-theme-color) 70%
$components-color-accent 33%,
$components-color-accent-darker-20 33%,
$components-color-accent-darker-20 70%,
$components-color-accent 70%
);
/* stylelint-enable */
border-color: var(--wp-admin-theme-color);
border-color: $components-color-accent;
}
}

Expand All @@ -114,13 +114,13 @@

&:active:not(:disabled) {
background: $gray-300;
color: var(--wp-admin-theme-color-darker-10);
color: $components-color-accent-darker-10;
box-shadow: none;
}

&:hover:not(:disabled) {
color: var(--wp-admin-theme-color-darker-10);
box-shadow: inset 0 0 0 $border-width var(--wp-admin-theme-color-darker-10);
color: $components-color-accent-darker-10;
box-shadow: inset 0 0 0 $border-width $components-color-accent-darker-10;
}

&:disabled,
Expand All @@ -140,10 +140,10 @@
*/

&.is-secondary {
box-shadow: inset 0 0 0 $border-width var(--wp-admin-theme-color);
box-shadow: inset 0 0 0 $border-width $components-color-accent;
outline: 1px solid transparent; // Shown in high contrast mode.
white-space: nowrap;
color: var(--wp-admin-theme-color);
color: $components-color-accent;
background: transparent;
}

Expand All @@ -153,7 +153,7 @@

&.is-tertiary {
white-space: nowrap;
color: var(--wp-admin-theme-color);
color: $components-color-accent;
background: transparent;
padding: $grid-unit-15 * 0.5; // This reduces the horizontal padding on tertiary/text buttons, so as to space them optically.

Expand Down Expand Up @@ -182,7 +182,7 @@
}

&:focus:not(:disabled) {
color: var(--wp-admin-theme-color);
color: $components-color-accent;
}

&:active:not(:disabled) {
Expand Down Expand Up @@ -230,7 +230,7 @@
background: none;
outline: none;
text-align: left;
color: var(--wp-admin-theme-color);
color: $components-color-accent;
text-decoration: underline;
transition-property: border, background, color;
transition-duration: 0.05s;
Expand All @@ -253,7 +253,7 @@
}

&:focus:not(:disabled) {
color: var(--wp-admin-theme-color);
color: $components-color-accent;
}
}
}
Expand Down Expand Up @@ -333,7 +333,7 @@
background: $gray-900;

&:focus:not(:disabled) {
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;

// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 2px solid transparent;
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export { Text as __experimentalText } from './text';
export { default as TextControl } from './text-control';
export { default as TextareaControl } from './textarea-control';
export { default as TextHighlight } from './text-highlight';
export { default as __experimentalTheme } from './theme';
export { default as Tip } from './tip';
export { default as ToggleControl } from './toggle-control';
export {
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/style.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Variables
@import "./utils/theme-variables.scss";

// Components
@import "./animate/style.scss";
@import "./autocomplete/style.scss";
@import "./button-group/style.scss";
Expand Down
34 changes: 34 additions & 0 deletions packages/components/src/theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Theme

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
</div>

`Theme` allows defining theme variables for components in the `@wordpress/components` package.

Multiple `Theme` components can be nested in order to override specific theme variables.

## Usage

```jsx
import { __experimentalTheme as Theme } from '@wordpress/components';

const Example = () => {
return (
<Theme accent="red">
<Button variant="primary">I'm red</Button>
<Theme accent="blue">
<Button variant="primary">I'm blue</Button>
</Theme>
</Theme>
);
};
```

## Props

### `accent`: `string`

Used to set the accent color (used by components as the primary color). If an accent color is not defined, the default fallback value is the original WP Admin main theme color. No all valid CSS color syntaxes are supported — in particular, keywords (like `'currentcolor'`, `'inherit'`, `'initial'`, `'revert'`, `'unset'`...) and CSS custom properties (e.g. `var(--my-custom-property)`) are _not_ supported values for this property.

- Required: No
51 changes: 51 additions & 0 deletions packages/components/src/theme/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* External dependencies
*/
import { colord, extend } from 'colord';
import a11yPlugin from 'colord/plugins/a11y';
import namesPlugin from 'colord/plugins/names';

/**
* Internal dependencies
*/
import type { ThemeProps } from './types';
import type { WordPressComponentProps } from '../ui/context';
import { Wrapper } from './styles';

extend( [ namesPlugin, a11yPlugin ] );

/**
* `Theme` allows defining theme variables for components in the `@wordpress/components` package.
*
* Multiple `Theme` components can be nested in order to override specific theme variables.
*
*
* @example
* ```jsx
* import { __experimentalTheme as Theme } from '@wordpress/components';
*
* const Example = () => {
* return (
* <Theme accent="red">
* <Button variant="primary">I'm red</Button>
* <Theme accent="blue">
* <Button variant="primary">I'm blue</Button>
* </Theme>
* </Theme>
* );
* };
* ```
*/
function Theme( props: WordPressComponentProps< ThemeProps, 'div', true > ) {
const { accent } = props;
if ( accent && ! colord( accent ).isValid() ) {
// eslint-disable-next-line no-console
console.warn(
`wp.components.Theme: "${ accent }" is not a valid color value for the 'accent' prop.`
);
}

return <Wrapper { ...props } />;
}

export default Theme;
47 changes: 47 additions & 0 deletions packages/components/src/theme/stories/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* External dependencies
*/
import type { ComponentMeta, ComponentStory } from '@storybook/react';

/**
* Internal dependencies
*/
import Theme from '../index';
import Button from '../../button';

const meta: ComponentMeta< typeof Theme > = {
component: Theme,
title: 'Components (Experimental)/Theme',
argTypes: {
accent: { control: { type: 'color' } },
},
parameters: {
controls: { expanded: true },
docs: { source: { state: 'open' } },
},
};
export default meta;

const Template: ComponentStory< typeof Theme > = ( args ) => (
<Theme { ...args }>
<Button variant="primary">Hello</Button>
</Theme>
);

export const Default = Template.bind( {} );
Default.args = {};

export const Nested: ComponentStory< typeof Theme > = ( args ) => (
<Theme accent="tomato">
<Button variant="primary">Outer theme (hardcoded)</Button>

<Theme { ...args }>
<Button variant="primary">
Inner theme (set via Storybook controls)
Copy link
Member Author

Choose a reason for hiding this comment

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

Good clarification!

</Button>
</Theme>
</Theme>
);
Nested.args = {
accent: 'blue',
};
28 changes: 28 additions & 0 deletions packages/components/src/theme/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* External dependencies
*/
import { colord } from 'colord';
import styled from '@emotion/styled';
import { css } from '@emotion/react';

/**
* Internal dependencies
*/
import type { ThemeProps } from './types';

const accentColor = ( { accent }: ThemeProps ) =>
accent
? css`
--wp-components-color-accent: ${ accent };
--wp-components-color-accent-darker-10: ${ colord( accent )
.darken( 0.1 )
.toHex() };
--wp-components-color-accent-darker-20: ${ colord( accent )
.darken( 0.2 )
.toHex() };
`
: undefined;

export const Wrapper = styled.div< ThemeProps >`
${ accentColor }
`;
Loading