diff --git a/package.json b/package.json index 1cd8535bfc803..ad1ecfa250416 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "@wordpress/shortcode": "file:packages/shortcode", "@wordpress/style-engine": "file:packages/style-engine", "@wordpress/sync": "file:packages/sync", + "@wordpress/theme": "file:packages/theme", "@wordpress/token-list": "file:packages/token-list", "@wordpress/undo-manager": "file:packages/undo-manager", "@wordpress/url": "file:packages/url", diff --git a/packages/components/src/base-control/styles/base-control-styles.ts b/packages/components/src/base-control/styles/base-control-styles.ts index abd2f3affc45a..f88e870899828 100644 --- a/packages/components/src/base-control/styles/base-control-styles.ts +++ b/packages/components/src/base-control/styles/base-control-styles.ts @@ -7,7 +7,7 @@ import { css } from '@emotion/react'; /** * Internal dependencies */ -import { baseLabelTypography, boxSizingReset, font, COLORS } from '../../utils'; +import { baseLabelTypography, boxSizingReset, font } from '../../utils'; import { space } from '../../ui/utils/space'; export const Wrapper = styled.div` @@ -64,7 +64,7 @@ export const StyledHelp = styled.p` margin-bottom: 0; font-size: ${ font( 'helpText.fontSize' ) }; font-style: normal; - color: ${ COLORS.gray[ 700 ] }; + color: var( --wp-theme-color-neutral-text-muted ); ${ deprecatedMarginHelp } `; diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss index b572e96e4335f..2362d041ec366 100644 --- a/packages/components/src/button/style.scss +++ b/packages/components/src/button/style.scss @@ -16,7 +16,7 @@ box-sizing: border-box; padding: 6px 12px; border-radius: $radius-block-ui; - color: $components-color-foreground; + color: var(--wp-theme-color-neutral-text); &.is-next-40px-default-size { height: $button-size-next-default-40px; @@ -48,8 +48,8 @@ &.is-primary { white-space: nowrap; - background: $components-color-accent; - color: $components-color-accent-inverted; + background: var(--wp-theme-color-primary-bg-strong); + color: var(--wp-theme-color-primary-text-inverse-strong); text-decoration: none; text-shadow: none; @@ -57,8 +57,7 @@ outline: 1px solid transparent; &:hover:not(:disabled) { - background: $components-color-accent-darker-10; - color: $components-color-accent-inverted; + background: var(--wp-theme-color-primary-bg-strong-hover); } &:active:not(:disabled) { diff --git a/packages/components/src/heading/hook.ts b/packages/components/src/heading/hook.ts index 13153bc853038..8c528fec6fe76 100644 --- a/packages/components/src/heading/hook.ts +++ b/packages/components/src/heading/hook.ts @@ -5,7 +5,7 @@ import type { WordPressComponentProps } from '../ui/context'; import { useContextSystem } from '../ui/context'; import { useText } from '../text'; import { getHeadingFontSize } from '../ui/utils/font-size'; -import { CONFIG, COLORS } from '../utils'; +import { CONFIG } from '../utils'; import type { HeadingProps } from './types'; export function useHeading( @@ -31,7 +31,7 @@ export function useHeading( } const textProps = useText( { - color: COLORS.gray[ 900 ], + color: 'var(--wp-theme-color-neutral-text-strong)', size: getHeadingFontSize( level ), isBlock: true, weight: CONFIG.fontWeightHeading as import('react').CSSProperties[ 'fontWeight' ], diff --git a/packages/components/src/input-control/styles/input-control-styles.tsx b/packages/components/src/input-control/styles/input-control-styles.tsx index 1bc75e2d82043..00d05b64ea6da 100644 --- a/packages/components/src/input-control/styles/input-control-styles.tsx +++ b/packages/components/src/input-control/styles/input-control-styles.tsx @@ -44,8 +44,8 @@ export const Root = styled( Flex )< RootProps >` const containerDisabledStyles = ( { disabled }: ContainerProps ) => { const backgroundColor = disabled - ? COLORS.ui.backgroundDisabled - : COLORS.ui.background; + ? 'var(--wp-theme-color-neutral-bg-disabled)' + : 'var(--wp-theme-color-neutral-bg-input)'; return css( { backgroundColor } ); }; @@ -211,7 +211,7 @@ export const Input = styled.input< InputProps >` box-sizing: border-box; border: none; box-shadow: none !important; - color: ${ COLORS.gray[ 900 ] }; + color: var( --wp-theme-color-neutral-text-strong ); display: block; font-family: inherit; margin: 0; @@ -268,7 +268,9 @@ const backdropFocusedStyles = ( { disabled, isFocused, }: BackdropProps ): SerializedStyles => { - let borderColor = isFocused ? COLORS.ui.borderFocus : COLORS.ui.border; + let borderColor = isFocused + ? 'var(--wp-theme-color-neutral-border-strong-hover)' + : 'var(--wp-theme-color-neutral-border-strong)'; let boxShadow; let outline; @@ -282,7 +284,7 @@ const backdropFocusedStyles = ( { } if ( disabled ) { - borderColor = COLORS.ui.borderDisabled; + borderColor = 'var(--wp-theme-color-neutral-border-disabled)'; } return css( { diff --git a/packages/components/src/search-control/style.scss b/packages/components/src/search-control/style.scss index d396cfd915083..3b79c2ff6c63b 100644 --- a/packages/components/src/search-control/style.scss +++ b/packages/components/src/search-control/style.scss @@ -3,9 +3,10 @@ input[type="search"].components-search-control__input { @include input-control; + color: var(--wp-theme-color-neutral-text-strong); display: block; padding: $grid-unit-20 $grid-unit-60 $grid-unit-20 $grid-unit-20; - background: $gray-100; + background: var(--wp-theme-color-neutral-bg); border: none; width: 100%; height: $grid-unit-60; @@ -21,12 +22,12 @@ } &:focus { - background: $white; + background: var(--wp-theme-color-neutral-bg-input); box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent; } &::placeholder { - color: $gray-700; + color: var(--wp-theme-color-neutral-text-muted); } &::-webkit-search-decoration, @@ -49,6 +50,7 @@ justify-content: center; > svg { + fill: var(--wp-theme-color-neutral-text); margin: $grid-unit-10 0; } } diff --git a/packages/components/src/text/styles.js b/packages/components/src/text/styles.js index 171e34fab9f46..bc6b8a1cbd869 100644 --- a/packages/components/src/text/styles.js +++ b/packages/components/src/text/styles.js @@ -9,7 +9,7 @@ import { css } from '@emotion/react'; import { COLORS, CONFIG } from '../utils'; export const Text = css` - color: ${ COLORS.gray[ 900 ] }; + color: var( --wp-theme-color-neutral-text ); line-height: ${ CONFIG.fontLineHeightBase }; margin: 0; `; @@ -27,7 +27,7 @@ export const destructive = css` `; export const muted = css` - color: ${ COLORS.gray[ 700 ] }; + color: var( --wp-theme-color-neutral-text-muted ); `; export const highlighterText = css` diff --git a/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts b/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts index e097f13cc6bf3..808ca4f973f45 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts +++ b/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts @@ -38,7 +38,7 @@ export const buttonView = ( { background: transparent; border: none; border-radius: ${ CONFIG.controlBorderRadius }; - color: ${ COLORS.gray[ 700 ] }; + color: var( --wp-theme-color-neutral-text ); fill: currentColor; cursor: pointer; display: flex; @@ -62,7 +62,7 @@ export const buttonView = ( { } &:active { - background: ${ CONFIG.toggleGroupControlBackgroundColor }; + background: var( --wp-theme-color-neutral-bg-strong ); } ${ isDeselectable && deselectable } @@ -71,7 +71,7 @@ export const buttonView = ( { `; const pressed = css` - color: ${ COLORS.white }; + color: var( --wp-theme-color-neutral-text-strong ); &:active { background: transparent; @@ -111,7 +111,7 @@ const isIconStyles = ( { }; export const backdropView = css` - background: ${ COLORS.gray[ 900 ] }; + background: var( --wp-theme-color-neutral-bg-active ); border-radius: ${ CONFIG.controlBorderRadius }; position: absolute; inset: 0; diff --git a/packages/components/src/toggle-group-control/toggle-group-control/styles.ts b/packages/components/src/toggle-group-control/toggle-group-control/styles.ts index 5d0b90096024c..85c00f1fb55c2 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/styles.ts +++ b/packages/components/src/toggle-group-control/toggle-group-control/styles.ts @@ -17,7 +17,7 @@ export const toggleGroupControl = ( { }: Pick< ToggleGroupControlProps, 'isBlock' | 'isDeselectable' > & { size: NonNullable< ToggleGroupControlProps[ 'size' ] >; } ) => css` - background: ${ COLORS.ui.background }; + background: var( --wp-theme-color-neutral-bg-input ); border: 1px solid transparent; border-radius: ${ CONFIG.controlBorderRadius }; display: inline-flex; @@ -31,14 +31,14 @@ export const toggleGroupControl = ( { const enclosingBorders = ( isBlock: ToggleGroupControlProps[ 'isBlock' ] ) => { const enclosingBorder = css` - border-color: ${ COLORS.ui.border }; + border-color: var( --wp-theme-color-neutral-border-strong ); `; return css` ${ isBlock && enclosingBorder } &:hover { - border-color: ${ COLORS.ui.borderHover }; + border-color: var( --wp-theme-color-neutral-border-strong-hover ); } &:focus-within { diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index a74742def329c..5402a6f8d4bfa 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -61,6 +61,7 @@ "@wordpress/reusable-blocks": "file:../reusable-blocks", "@wordpress/router": "file:../router", "@wordpress/style-engine": "file:../style-engine", + "@wordpress/theme": "file:../theme", "@wordpress/url": "file:../url", "@wordpress/viewport": "file:../viewport", "@wordpress/widgets": "file:../widgets", diff --git a/packages/edit-site/src/components/app/index.js b/packages/edit-site/src/components/app/index.js index cad76b3ea1fb8..c6e0b0e68cfe1 100644 --- a/packages/edit-site/src/components/app/index.js +++ b/packages/edit-site/src/components/app/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { SlotFillProvider } from '@wordpress/components'; +import { ThemeProvider } from '@wordpress/theme'; import { UnsavedChangesWarning } from '@wordpress/editor'; import { store as noticesStore } from '@wordpress/notices'; import { useDispatch } from '@wordpress/data'; @@ -34,14 +35,16 @@ export default function App() { } return ( - - - - - - - - - + + + + + + + + + + + ); } diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index 80950d130a0a1..292fb97f0cf8a 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -7,6 +7,7 @@ import classnames from 'classnames'; * WordPress dependencies */ import { useSelect } from '@wordpress/data'; +import { ThemeProvider } from '@wordpress/theme'; import { __unstableMotion as motion, __unstableAnimatePresence as AnimatePresence, @@ -256,7 +257,9 @@ export default function Layout() { ease: 'easeOut', } } > -
+ +
+ ) } @@ -368,11 +371,13 @@ export default function Layout() { backgroundColor, } } > - + + + diff --git a/packages/edit-site/src/components/layout/style.scss b/packages/edit-site/src/components/layout/style.scss index 11c7bdeeaf2a1..01e610cc9874e 100644 --- a/packages/edit-site/src/components/layout/style.scss +++ b/packages/edit-site/src/components/layout/style.scss @@ -1,7 +1,7 @@ .edit-site-layout { height: 100%; - background: $gray-900; - color: $gray-400; + background: var(--wp-theme-color-neutral-bg-muted); + color: var(--wp-theme-color-neutral-text); display: flex; flex-direction: column; } diff --git a/packages/edit-site/src/components/page-patterns/style.scss b/packages/edit-site/src/components/page-patterns/style.scss index 4b4d7bb9059d4..42ffafecd9866 100644 --- a/packages/edit-site/src/components/page-patterns/style.scss +++ b/packages/edit-site/src/components/page-patterns/style.scss @@ -1,5 +1,5 @@ .edit-site-patterns { - border-left: 1px solid $gray-800; + border-left: 1px solid var(--wp-theme-color-neutral-border); background: none; margin: $header-height 0 0; border-radius: 0; @@ -13,14 +13,6 @@ } } - .components-text { - color: $gray-600; - } - - .components-heading { - color: $gray-200; - } - @include break-medium { margin: 0; } @@ -35,22 +27,10 @@ .edit-site-patterns__search { input[type="search"] { height: $button-size-next-default-40px; - background: $gray-800; - color: $gray-200; - - &:focus { - background: $gray-800; - } - } - - svg { - fill: $gray-600; } } .edit-site-patterns__sync-status-filter { - background: $gray-800; - border: none; height: $button-size-next-default-40px; min-width: max-content; width: 100%; @@ -60,17 +40,10 @@ width: 300px; } } - .edit-site-patterns__sync-status-filter-option:not([aria-checked="true"]) { - color: $gray-600; - } - .edit-site-patterns__sync-status-filter-option:active { - background: $gray-700; - color: $gray-100; - } .edit-site-patterns__grid-pagination { - border-top: 1px solid $gray-800; - background: $gray-900; + border-top: 1px solid var(--wp-theme-color-neutral-border); + background: var(--wp-theme-color-neutral-bg-muted); padding: $grid-unit-30 $grid-unit-40; position: sticky; bottom: 0; @@ -79,17 +52,18 @@ .components-button.is-tertiary { width: $button-size-compact; height: $button-size-compact; - color: $gray-100; - background-color: $gray-800; + color: var(--wp-theme-color-neutral-text); + background-color: var(--wp-theme-color-neutral-bg); justify-content: center; &:disabled { - color: $gray-600; + color: var(--wp-theme-color-neutral-text-muted); background: none; } &:hover:not(:disabled) { - background-color: $gray-700; + background-color: var(--wp-theme-color-neutral-bg-hover); + color: var(--wp-theme-color-neutral-text-hover); } } } @@ -98,7 +72,7 @@ .edit-site-patterns__header { position: sticky; top: 0; - background: $gray-900; + background: var(--wp-theme-color-neutral-bg-muted); padding: $grid-unit-40 $grid-unit-40 $grid-unit-20; z-index: z-index(".edit-site-patterns__header"); } @@ -192,16 +166,9 @@ } .edit-site-patterns__pattern-title { - color: $gray-200; - .is-link { text-decoration: none; - color: $gray-200; - - &:hover, - &:focus { - color: $white; - } + color: var(--wp-theme-color-neutral-text-strong); } .edit-site-patterns__pattern-icon { diff --git a/packages/edit-site/src/components/page/style.scss b/packages/edit-site/src/components/page/style.scss index 8da7df8e0385b..51cc3172d4525 100644 --- a/packages/edit-site/src/components/page/style.scss +++ b/packages/edit-site/src/components/page/style.scss @@ -1,5 +1,5 @@ .edit-site-page { - color: $gray-800; + color: var(--wp-theme-color-neutral-text); background: $white; flex-grow: 1; overflow: hidden; @@ -14,20 +14,14 @@ .edit-site-page-header { padding: 0 $grid-unit-40; min-height: $header-height; - border-bottom: 1px solid $gray-100; + border-bottom: 1px solid var(--wp-theme-color-neutral-border); background: $white; position: sticky; top: 0; z-index: z-index(".edit-site-page-header"); - .components-text { - color: $gray-800; - } - .components-heading { - color: $gray-900; - } .edit-site-page-header__sub-title { margin-top: $grid-unit-10; - color: $gray-700; + color: var(--wp-theme-color-neutral-text); } } diff --git a/packages/edit-site/src/components/save-hub/style.scss b/packages/edit-site/src/components/save-hub/style.scss index e864444b2077b..ed44a48c00768 100644 --- a/packages/edit-site/src/components/save-hub/style.scss +++ b/packages/edit-site/src/components/save-hub/style.scss @@ -1,6 +1,6 @@ .edit-site-save-hub { - color: $gray-600; - border-top: 1px solid $gray-800; + color: var(--wp-theme-color-neutral-text); + border-top: 1px solid var(--wp-theme-color-neutral-border); flex-shrink: 0; margin: 0; padding: $grid-unit-20 + $grid-unit-05 $canvas-padding; diff --git a/packages/edit-site/src/components/sidebar-button/style.scss b/packages/edit-site/src/components/sidebar-button/style.scss index 5135f97869bb8..95344065b32eb 100644 --- a/packages/edit-site/src/components/sidebar-button/style.scss +++ b/packages/edit-site/src/components/sidebar-button/style.scss @@ -1,5 +1,5 @@ .edit-site-sidebar-button { - color: $gray-200; + color: var(--wp-theme-color-neutral-text); flex-shrink: 0; // Focus (resets default button focus and use focus-visible). @@ -19,6 +19,6 @@ &:focus, &:not([aria-disabled="true"]):active, &[aria-expanded="true"] { - color: $gray-100; + color: var(--wp-theme-color-neutral-text-hover); } } diff --git a/packages/edit-site/src/components/sidebar-navigation-item/style.scss b/packages/edit-site/src/components/sidebar-navigation-item/style.scss index 88ff27a9c1d2f..9675468e88e26 100644 --- a/packages/edit-site/src/components/sidebar-navigation-item/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-item/style.scss @@ -1,5 +1,5 @@ .edit-site-sidebar-navigation-item.components-item { - color: $gray-600; + color: var(--wp-theme-color-neutral-text); // 6px right padding to align with + button padding: $grid-unit-10 6px $grid-unit-10 $grid-unit-20; border: none; @@ -9,21 +9,21 @@ &:hover, &:focus, &[aria-current] { - color: $gray-200; - background: $gray-800; + color: var(--wp-theme-color-neutral-text-strong); + background: var(--wp-theme-color-neutral-bg-hover); .edit-site-sidebar-navigation-item__drilldown-indicator { - fill: $gray-200; + fill: var(--wp-theme-color-neutral-text-strong); } } &[aria-current] { background: var(--wp-admin-theme-color); - color: $white; + color: var(--wp-theme-color-neutral-text-inverse); } .edit-site-sidebar-navigation-item__drilldown-indicator { - fill: $gray-600; + fill: var(--wp-theme-color-neutral-text); } &.with-suffix { diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-details-panel/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen-details-panel/style.scss index 2757ce5a620c5..e7feb3d46e84c 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-details-panel/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen-details-panel/style.scss @@ -6,7 +6,6 @@ } .edit-site-sidebar-navigation-details-screen-panel__heading { - color: $gray-400; text-transform: uppercase; font-weight: 500; font-size: 11px; @@ -16,11 +15,11 @@ } .edit-site-sidebar-navigation-details-screen-panel__label.edit-site-sidebar-navigation-details-screen-panel__label { - color: $gray-600; + color: var(--wp-theme-color-neutral-text-muted); width: 100px; flex-shrink: 0; } .edit-site-sidebar-navigation-details-screen-panel__value.edit-site-sidebar-navigation-details-screen-panel__value { - color: $gray-200; + color: var(--wp-theme-color-neutral-text); } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/style.scss index 525dd68d3b9f7..e9eeca5770064 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/style.scss @@ -9,7 +9,7 @@ &:hover, &:focus, &[aria-current] { - background: $gray-800; + background: var(--wp-theme-color-neutral-bg-hover); } .block-editor-list-view-block__menu { margin-left: -$grid-unit-10; @@ -31,7 +31,7 @@ &:hover, &:focus { - color: $white; + color: var(--wp-theme-color-neutral-text-hover); .block-editor-list-view-block__menu-cell { opacity: 1; @@ -59,7 +59,7 @@ background: transparent; &:hover { - background: $gray-800; + background: var(--wp-theme-color-neutral-bg-hover); } } } @@ -81,11 +81,12 @@ } .components-button { - color: $gray-600; + color: var(--wp-theme-color-neutral-text); &:hover, &:focus, &[aria-current] { - color: $white; + color: var(--wp-theme-color-neutral-text-hover); + background-color: var(--wp-theme-color-neutral-bg-hover); } } } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen/index.js b/packages/edit-site/src/components/sidebar-navigation-screen/index.js index 9ab6f58c81b21..4d19374c48678 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen/index.js @@ -100,7 +100,6 @@ export default function SidebarNavigationScreen( { ) } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss index 974a0e70c4cf6..7c3a4596a0ac6 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss @@ -23,10 +23,6 @@ margin-right: -$grid-unit-20; } - .components-text { - color: $gray-400; - } - .components-heading { margin-bottom: $grid-unit-10; } @@ -34,11 +30,7 @@ .edit-site-sidebar-navigation-screen__meta { margin: 0 0 $grid-unit-20 0; - color: $gray-400; margin-left: $grid-unit-20; - .components-text { - color: $gray-400; - } } .edit-site-sidebar-navigation-screen__page-link { @@ -58,7 +50,7 @@ .edit-site-sidebar-navigation-screen__title-icon { position: sticky; top: 0; - background: $gray-900; + background: var(--wp-theme-color-neutral-bg-muted); padding-top: $grid-unit-60 + $header-height; margin-bottom: $grid-unit-10; padding-bottom: $grid-unit-10; @@ -78,7 +70,7 @@ .edit-site-sidebar-navigation-screen__content .edit-site-global-styles-style-variations-container { .edit-site-global-styles-variations_item-preview { - border: $gray-900 $border-width solid; + border: var(--wp-theme-) $border-width solid; } .edit-site-global-styles-variations_item.is-active .edit-site-global-styles-variations_item-preview { border: $gray-100 $border-width solid; @@ -95,16 +87,16 @@ .edit-site-sidebar-navigation-screen__footer { position: sticky; bottom: 0; - background-color: $gray-900; + background-color: var(--wp-theme-color-neutral-bg-muted); gap: 0; padding: $grid-unit-20 0; margin: $grid-unit-20 0 0; - border-top: 1px solid $gray-800; + border-top: 1px solid var(--wp-theme-color-neutral-border); } .edit-site-sidebar__notice { - background: $gray-800; - color: $gray-300; + background: var(--wp-theme-color-neutral-bg); + color: var(--wp-theme-color-neutral-text); margin: $grid-unit-30 0; &.is-dismissible { padding-right: $grid-unit-10; @@ -124,22 +116,4 @@ */ .edit-site-sidebar-navigation-screen__input-control { width: 100%; - .components-input-control__container { - background: $gray-800; - - .components-button { - color: $gray-200 !important; - } - } - .components-input-control__input { - color: $gray-200 !important; - background: $gray-800 !important; - border-radius: $radius-block-ui; - } - .components-input-control__backdrop { - border: 4px !important; - } - .components-base-control__help { - color: $gray-600; - } } diff --git a/packages/edit-site/src/components/site-hub/style.scss b/packages/edit-site/src/components/site-hub/style.scss index 49e5304d1688f..277f224cff762 100644 --- a/packages/edit-site/src/components/site-hub/style.scss +++ b/packages/edit-site/src/components/site-hub/style.scss @@ -27,9 +27,6 @@ &:focus { opacity: 1; } - svg { - fill: $gray-200; - } } &:hover { .edit-site-site-hub__site-view-link { @@ -46,7 +43,7 @@ height: $header-height; width: $header-height; flex-shrink: 0; - background: $gray-900; + background: var(--wp-theme-color-neutral-bg-muted); &.has-transparent-background { background: transparent; @@ -67,13 +64,13 @@ .edit-site-site-hub__site-title { margin-left: $grid-unit-05; flex-grow: 1; - color: $gray-200; + color: var(--wp-theme-color-neutral-text-strong); } .edit-site-site-hub_toggle-command-center { - color: $gray-200; + color: var(--wp-theme-color-neutral-text); &:hover { - color: $gray-100; + color: var(--wp-theme-color-neutral-text-hover); } } diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 111696241d0d6..5c0472e7b567d 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -103,6 +103,10 @@ body.js.site-editor-php { } } +.edit-site-theme { + height: 100%; +} + /** * Animations */ diff --git a/packages/theme/builders/css-properties-from-theme.js b/packages/theme/builders/css-properties-from-theme.js new file mode 100644 index 0000000000000..da110ec82df4a --- /dev/null +++ b/packages/theme/builders/css-properties-from-theme.js @@ -0,0 +1,24 @@ +/** + * Internal dependencies + */ + +import { defaultTheme } from '../theme.js'; +import { themeToCss } from '../utils.js'; + +printStylesheet( defaultTheme ); + +function printStylesheet( theme ) { + const css = themeToCss( theme ); + + const contents = [ + `/* Generated by WordPress */`, + '\n\n', + ':root {', + '\n', + css, + '\n', + '}', + ]; + + return contents; +} diff --git a/packages/theme/color.js b/packages/theme/color.js new file mode 100644 index 0000000000000..987d7c93290ea --- /dev/null +++ b/packages/theme/color.js @@ -0,0 +1,131 @@ +/** + * External dependencies + */ +import { colord, extend } from 'colord'; +import a11yPlugin from 'colord/plugins/a11y'; +import namesPlugin from 'colord/plugins/names'; + +extend( [ namesPlugin, a11yPlugin ] ); + +const LIGHT_VALUES = [ 100, 98, 95, 92, 89, 87, 83, 73, 55, 48, 39, 13 ]; +const DARK_VALUES = [ 1, 11, 16, 19, 22, 18, 29, 38, 43, 73, 80, 93 ]; +export const PRIMARY_DEFAULT = '#3858e9'; + +// map showing which lightness in scale each use case should use +const COLOR_MAP = { + bg: { + default: 2, + hover: 3, + active: 4, + input: { + default: 0, + disabled: 0, + }, + muted: 1, + strong: { + default: 8, + hover: 9, + }, + }, + text: { + default: 10, + hover: 11, + strong: 11, + inverse: { + default: 1, + strong: 0, + }, + muted: 9, + }, + border: { + default: 5, + disabled: 4, + input: 6, + strong: { + default: 6, + hover: 7, + }, + muted: 4, + hover: 6, + }, +}; + +// generates a color palette based on a primary color +export const generateColors = ( { + color = PRIMARY_DEFAULT, + fun = 0, + isDark = false, +} ) => { + const neutral = generateNeutralColors( { color, fun, isDark } ); + const primary = generatePrimaryColors( { + color, + bg: neutral.bg.default, + isDark, + } ); + + return { + primary, + neutral, + }; +}; + +const generateNeutralColors = ( { + color = PRIMARY_DEFAULT, + fun = 0, + isDark = false, +} ) => { + const base = colord( color ).toHsl(); + const lightValues = isDark ? DARK_VALUES : LIGHT_VALUES; + const colors = lightValues.map( ( value ) => + colord( { ...base, s: fun, l: value } ).toHex() + ); + return mapColors( colors, COLOR_MAP ); +}; + +const generatePrimaryColors = ( { + color = PRIMARY_DEFAULT, + bg, + isDark = false, +} ) => { + const base = colord( color ).toHsl(); + const lightValues = isDark ? DARK_VALUES : LIGHT_VALUES; + + // if the color given has enough contrast agains the background, use that as the solid background colour and adjust the surrounding scale to proportionally move with it + const length = lightValues.length; + // Calculate the difference between the new value and the old value + const diff = base.l - lightValues[ 8 ]; + // Calculate the weight for adjusting values. Closer to base colour should adjust more. + const weight = ( index ) => 1 - Math.abs( 8 - index ) / ( length - 1 ); + // Adjust all values in the array based on their weight + let adjustedArray = [ ...lightValues ]; + if ( colord( bg ).isReadable( base ) ) { + adjustedArray = lightValues.map( ( value, index ) => { + const adjustment = diff * weight( index ); + return index === 8 ? base.l : value + adjustment; + } ); + } + + // convert colours to hex and set min and max lightness values + const colors = adjustedArray.map( ( value ) => + colord( { + ...base, + l: Math.min( Math.max( parseInt( value ), 0 ), 100 ), + } ).toHex() + ); + + return mapColors( colors, COLOR_MAP ); +}; + +// maps a color map to a color palette +const mapColors = ( mapFromArray, mapToObject ) => { + const map = {}; + Object.keys( mapToObject ).forEach( ( alias ) => { + const color = mapToObject[ alias ]; + if ( typeof color === 'object' ) { + map[ alias ] = mapColors( mapFromArray, color ); + } else { + map[ alias ] = mapFromArray[ parseInt( color ) ]; + } + } ); + return map; +}; diff --git a/packages/theme/index.js b/packages/theme/index.js new file mode 100644 index 0000000000000..e4de33d613595 --- /dev/null +++ b/packages/theme/index.js @@ -0,0 +1,2 @@ +export { ThemeProvider } from './provider'; +export { defaultTheme } from './theme'; diff --git a/packages/theme/package.json b/packages/theme/package.json new file mode 100644 index 0000000000000..4164cb34d8a2d --- /dev/null +++ b/packages/theme/package.json @@ -0,0 +1,34 @@ +{ + "name": "@wordpress/theme", + "version": "1.0.0", + "description": "A collection of tokens that make up a WordPress theme.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ + "theme", + "variables", + "styles" + ], + "homepage": "https://github.com/WordPress/gutenberg", + "repository": { + "type": "git", + "url": "git+https://github.com/WordPress/gutenberg.git", + "directory": "packages/theme" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "files": [ + "index.js", + "style.scss" + ], + "main": "index.js", + "style": "style.scss", + "dependencies": { + "@wordpress/element": "file:../element", + "colord": "^2.7.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/theme/provider.js b/packages/theme/provider.js new file mode 100644 index 0000000000000..036991d8971ef --- /dev/null +++ b/packages/theme/provider.js @@ -0,0 +1,60 @@ +/** + * WordPress dependencies + */ +import { createElement } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { generateColors } from './color'; +import { themeToCss } from './utils'; + +// lightweight way to add styles to a class name +const toHash = ( str ) => { + let i = 0, + out = 11; + while ( i < str.length ) out = ( 101 * out + str.charCodeAt( i++ ) ) >>> 0; //eslint-disable-line no-bitwise + return 'wp-' + out; +}; + +const addStyle = ( target, className, cssText ) => { + const style = document.createElement( 'style' ); + style.id = className; + style.append( cssText ); + target.append( style ); +}; + +const merge = ( compiled, target ) => { + const name = toHash( compiled ); + if ( ! document.getElementById( name ) ) { + addStyle( target, name, `.${ name } { ${ compiled }}` ); + } + return name; +}; + +// theme provider component that generates a theme and adds appropriate tokens to the head +export const ThemeProvider = ( { + as = 'div', + color, + fun, + isDark, + ...props +} ) => { + const { className, children, ...rest } = props; + const styles = themeToCss( { + color: generateColors( { + color, + fun, + isDark, + } ), + } ); + const name = merge( styles, document.head ); + return createElement( + as, + { + className: [ name, className ].join( ' ' ), + ...rest, + }, + children + ); +}; diff --git a/packages/theme/style.scss b/packages/theme/style.scss new file mode 100644 index 0000000000000..4dde33074beac --- /dev/null +++ b/packages/theme/style.scss @@ -0,0 +1,25 @@ +:root { + --wp-theme-color-neutral-bg-surface: var(--wp-theme-color-neutral-1); + --wp-theme-color-neutral-bg-input: var(--wp-theme-color-neutral-1); + --wp-theme-color-neutral-text-inverse-strong: var(--wp-theme-color-neutral-1); + --wp-theme-color-neutral-bg-input-disabled: var(--wp-theme-color-neutral-1); + --wp-theme-color-neutral-bg-muted: var(--wp-theme-color-neutral-2); + --wp-theme-color-neutral-text-inverse: var(--wp-theme-color-neutral-2); + --wp-theme-color-neutral-bg: var(--wp-theme-color-neutral-3); + --wp-theme-color-neutral-bg-hover: var(--wp-theme-color-neutral-4); + --wp-theme-color-neutral-bg-active: var(--wp-theme-color-neutral-5); + --wp-theme-color-neutral-border: var(--wp-theme-color-neutral-6); + --wp-theme-color-neutral-border-disabled: var(--wp-theme-color-neutral-6); + --wp-theme-color-neutral-border-input: var(--wp-theme-color-neutral-7); + --wp-theme-color-neutral-border-strong: var(--wp-theme-color-neutral-7); + --wp-theme-color-neutral-border-hover: var(--wp-theme-color-neutral-7); + --wp-theme-color-neutral-border-strong-hover: var(--wp-theme-color-neutral-8); + --wp-theme-color-neutral-bg-strong: var(--wp-theme-color-neutral-9); + --wp-theme-color-neutral-bg-strong-hover: var(--wp-theme-color-neutral-10); + --wp-theme-color-neutral-text-muted: var(--wp-theme-color-neutral-10); + --wp-theme-color-neutral-text: var(--wp-theme-color-neutral-11); + --wp-theme-color-neutral-text-hover: var(--wp-theme-color-neutral-12); + --wp-theme-color-neutral-text-strong: var(--wp-theme-color-neutral-12); + --wp-theme-color-neutral-bg-inverse: var(--wp-theme-color-neutral-12); +} + diff --git a/packages/theme/theme.js b/packages/theme/theme.js new file mode 100644 index 0000000000000..0fd578185a144 --- /dev/null +++ b/packages/theme/theme.js @@ -0,0 +1,16 @@ +/** + * Internal dependencies + */ +import { generateColors } from './color'; + +// // theme object +export const defaultTheme = { + // shadows: {...}, + // spacing: { ... }, + // borderRadius: { ... }, + // fonts: { ... }, + // fontSizes: { ... }, + // fontWeights: { ... }, + // lineHeights: { ... }, + colors: generateColors( {} ), +}; diff --git a/packages/theme/utils.js b/packages/theme/utils.js new file mode 100644 index 0000000000000..877037102b030 --- /dev/null +++ b/packages/theme/utils.js @@ -0,0 +1,20 @@ +// flattens the theme object to a single level +function flattenTheme( obj, parent, res = {} ) { + for ( const key in obj ) { + const propName = parent ? parent + '-' + key : key; + if ( typeof obj[ key ] === 'object' ) { + flattenTheme( obj[ key ], propName, res ); + } else { + res[ propName.replace( '-default', '' ) ] = obj[ key ]; + } + } + return res; +} + +// converts a theme object to a CSS string containing CSS variables +export const themeToCss = ( theme ) => { + const flattenedTheme = flattenTheme( theme ); + return Object.entries( flattenedTheme ) + .map( ( [ key, value ] ) => `--wp-theme-${ key }: ${ value };` ) + .join( '\n' ); +};