From ad13f49f35250923b4f7475ac9bc5f16345a56f7 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Thu, 8 Apr 2021 10:40:36 -0700 Subject: [PATCH 01/19] Components: Add styles --- .../src/ui/styles/components/README.md | 34 ++ .../src/ui/styles/components/box.js | 8 + .../src/ui/styles/components/index.js | 2 + .../styles/components/style-frame-provider.js | 221 +++++++++++ packages/components/src/ui/styles/core.js | 1 + packages/components/src/ui/styles/css.js | 134 +++++++ .../components/src/ui/styles/hooks/index.js | 2 + .../ui/styles/hooks/use-responsive-value.js | 88 +++++ .../components/src/ui/styles/hooks/use-rtl.js | 6 + packages/components/src/ui/styles/index.js | 10 + .../components/src/ui/styles/mixins/flow.js | 55 +++ .../components/src/ui/styles/mixins/index.js | 2 + .../components/src/ui/styles/mixins/space.js | 14 + .../components/src/ui/styles/namespaces.js | 19 + .../components/src/ui/styles/presets/flow.js | 17 + .../components/src/ui/styles/style-system.js | 18 + packages/components/src/ui/styles/styled.js | 1 + packages/components/src/ui/styles/system.js | 181 +++++++++ .../ui/styles/test/component-interpolation.js | 161 ++++++++ packages/components/src/ui/styles/test/css.js | 36 +- .../components/src/ui/styles/test/scales.js | 49 +++ .../components/src/ui/styles/test/styled.js | 43 +- .../components/src/ui/styles/theme/config.js | 370 ++++++++++++++++++ .../src/ui/styles/theme/create-theme.js | 44 +++ .../theme/dark-high-contrast-mode-config.js | 7 + .../src/ui/styles/theme/dark-mode-config.js | 44 +++ .../styles/theme/high-contrast-mode-config.js | 7 + .../components/src/ui/styles/theme/index.js | 2 + .../components/src/ui/styles/theme/theme.js | 31 ++ .../src/ui/styles/theme/tokens/colors.js | 206 ++++++++++ .../src/ui/styles/theme/tokens/index.js | 1 + .../components/src/ui/styles/theme/utils.js | 122 ++++++ packages/components/src/ui/utils/colors.js | 39 ++ 33 files changed, 1914 insertions(+), 61 deletions(-) create mode 100644 packages/components/src/ui/styles/components/README.md create mode 100644 packages/components/src/ui/styles/components/box.js create mode 100644 packages/components/src/ui/styles/components/index.js create mode 100644 packages/components/src/ui/styles/components/style-frame-provider.js create mode 100644 packages/components/src/ui/styles/core.js create mode 100644 packages/components/src/ui/styles/css.js create mode 100644 packages/components/src/ui/styles/hooks/index.js create mode 100644 packages/components/src/ui/styles/hooks/use-responsive-value.js create mode 100644 packages/components/src/ui/styles/hooks/use-rtl.js create mode 100644 packages/components/src/ui/styles/index.js create mode 100644 packages/components/src/ui/styles/mixins/flow.js create mode 100644 packages/components/src/ui/styles/mixins/index.js create mode 100644 packages/components/src/ui/styles/mixins/space.js create mode 100644 packages/components/src/ui/styles/namespaces.js create mode 100644 packages/components/src/ui/styles/presets/flow.js create mode 100644 packages/components/src/ui/styles/style-system.js create mode 100644 packages/components/src/ui/styles/styled.js create mode 100644 packages/components/src/ui/styles/system.js create mode 100644 packages/components/src/ui/styles/test/component-interpolation.js create mode 100644 packages/components/src/ui/styles/test/scales.js create mode 100644 packages/components/src/ui/styles/theme/config.js create mode 100644 packages/components/src/ui/styles/theme/create-theme.js create mode 100644 packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js create mode 100644 packages/components/src/ui/styles/theme/dark-mode-config.js create mode 100644 packages/components/src/ui/styles/theme/high-contrast-mode-config.js create mode 100644 packages/components/src/ui/styles/theme/index.js create mode 100644 packages/components/src/ui/styles/theme/theme.js create mode 100644 packages/components/src/ui/styles/theme/tokens/colors.js create mode 100644 packages/components/src/ui/styles/theme/tokens/index.js create mode 100644 packages/components/src/ui/styles/theme/utils.js diff --git a/packages/components/src/ui/styles/components/README.md b/packages/components/src/ui/styles/components/README.md new file mode 100644 index 0000000000000..bdd111840e65a --- /dev/null +++ b/packages/components/src/ui/styles/components/README.md @@ -0,0 +1,34 @@ +# Components + +## StyleFrameProvider + +This component ensures styles generated by the Style System work when components are rendered within an iFrame. + +### Usage + +Wrap any components using the Style System with the `StyleFrameProvider` when rendering within an iFrame. + +```jsx +import { StyleFrameProvider } from '@wp-g2/styles'; +import { View } from '@wp-g2/components'; +import Frame from 'react-frame-component'; // Works with any iFrame component. + +function Example() { + return ( + + + ... + + + ); +} +``` + +### Problem + +By default, [CSS-in-JS](https://emotion.sh/docs/introduction) system injects styles to the `document` `` of the main `window`. Under regular use-cases, this works perfectly fine, as there would ever be a single window. However, with iFrames, the styles need to inject to the iFrame's `window`. + +### Solution + +The `StyleFrameProvider` coordinates with the Style System's renderer to ensure that the styles are injected to the **correct** `window`. + diff --git a/packages/components/src/ui/styles/components/box.js b/packages/components/src/ui/styles/components/box.js new file mode 100644 index 0000000000000..e1897a4a39607 --- /dev/null +++ b/packages/components/src/ui/styles/components/box.js @@ -0,0 +1,8 @@ +/** + * Internal dependencies + */ +import { core } from '../core'; + +export const Box = core.div; +export const BaseView = Box; +export const View = Box; diff --git a/packages/components/src/ui/styles/components/index.js b/packages/components/src/ui/styles/components/index.js new file mode 100644 index 0000000000000..65d68d9097770 --- /dev/null +++ b/packages/components/src/ui/styles/components/index.js @@ -0,0 +1,2 @@ +export * from './box'; +export * from './style-frame-provider'; diff --git a/packages/components/src/ui/styles/components/style-frame-provider.js b/packages/components/src/ui/styles/components/style-frame-provider.js new file mode 100644 index 0000000000000..2f25a353280ac --- /dev/null +++ b/packages/components/src/ui/styles/components/style-frame-provider.js @@ -0,0 +1,221 @@ +/** + * WordPress dependencies + */ +import { useEffect, useRef } from '@wordpress/element'; +import warn from '@wordpress/warning'; + +/** + * Internal dependencies + */ +import { compiler } from '../system'; + +const { cache } = compiler; + +/** + * @typedef StyleFrameProviderProps + * @property {import('react').ReactNode} children Children elements to render. + */ + +/** + * A special Provider designed specifically for iFrame usage. + * Components using `@wp-g2/styled` that render within will have their + * styles injected and rendered correctly within the iFrame out-of-the-box. + * + * No external stylesheet loading is necessary when using . + * + * @example + * ```jsx + * + * + * + * + * + * ``` + * + * @param {StyleFrameProviderProps} props Props for the Provider. + */ +export function StyleFrameProvider( { children } ) { + const ref = useRef( null ); + useEmotionSheetInsert( { ref } ); + useEmotionInitialTagSync( { ref } ); + + /** + * Rendering the contents within a
in order for React + * to retrieve the correct Frame.document (via ownerDocument.) + */ + return
{ children }
; +} + +/** + * Initially syncs existing Emotion tags (from cache) into the Frame head by + * cloning and injecting the tags into the DOM. + * + * @param {Object} options + * @param {import('react').RefObject} options.ref + */ +function useEmotionInitialTagSync( { ref } ) { + useEffect( () => { + const ownerDocument = ref.current?.ownerDocument; + if ( ! ownerDocument ) return; + + const head = ownerDocument.querySelector( 'head' ); + + try { + /** + * Account for compiler (Emotion) isSpeedy rendering, which occurs + * for production builds. + */ + // @ts-ignore isSpeedy is an unexposed property + if ( cache.sheet.isSpeedy ) { + let speedyTag = cache.sheet.tags[ 0 ]; + /** + * Locate the styleSheet instance within document.styleSheet + * based on the speed (style) tag match. + */ + const speedySheet = Object.values( document.styleSheets ).find( + ( sheet ) => sheet.ownerNode === speedyTag + ); + if ( speedySheet ) { + /** + * The compiler's speedy mode inserts the cssRule directly + * into the styleSheet instance, rather than as a textNode in + * a style tag. We can retrieve this via the styleSheet instance + * cssRule. + */ + const initialStyles = Object.values( speedySheet.cssRules ) + .map( ( cssRule ) => cssRule.cssText ) + .join( '\n' ); + + /** + * Clone the speed style tag, and append it into the target (frame) + * document head. + */ + // @ts-ignore cloneNode type is weak + speedyTag = speedyTag.cloneNode( true ); + speedyTag.innerHTML = initialStyles; + + if ( head ) { + head.appendChild( speedyTag ); + } + } + } else if ( cache.sheet.tags ) { + /** + * Otherwise, loop through all of the cache sheet tags, and clone + * them into the targeted (frame) document head. + */ + cache.sheet.tags.forEach( ( tag ) => { + if ( head ) { + head.appendChild( tag.cloneNode( true ) ); + } + } ); + } + } catch ( e ) { + warn( + `There was a problem syncing Style rules from window.document. ${ e }` + ); + } + }, [ ref ] ); +} + +/** + * Inserts individual rules compiled by Emotion into the Frame's + * document.styleSheet object by using the same technique as Emotion's + * sheet class. + * + * @param {Object} props + * @param {import('react').RefObject} props.ref + */ +function useEmotionSheetInsert( { ref } ) { + /** + * The following insert code is found in Emotion's sheet class, specifically, + * the insert method. We're replicating that functionality to insert + * the style rules into the Frame's container (document.head). + * + * https://github.com/emotion-js/emotion/blob/master/packages/sheet/src/index.js + */ + useEffect( () => { + const ownerDocument = ref.current?.ownerDocument; + if ( ! ownerDocument ) return; + + const head = ownerDocument.querySelector( 'head' ); + + if ( ! head ) { + return; + } + + const sheetForTag = () => { + let tag = head.querySelector( 'style[data-style-system-frame]' ); + + if ( ! tag ) { + tag = ownerDocument.createElement( 'style' ); + tag.setAttribute( 'data-style-system-frame', 'true' ); + head.appendChild( tag ); + } + + const sheet = /** @type {HTMLStyleElement} */ ( tag ).sheet; + + if ( sheet ) { + return sheet; + } + + // this weirdness brought to you by firefox + for ( let i = 0; i < ownerDocument.styleSheets.length; i++ ) { + if ( ownerDocument.styleSheets[ i ].ownerNode === tag ) { + return ownerDocument.styleSheets[ i ]; + } + } + + throw new Error( 'Unable to find sheet for tag' ); + }; + + const renderStyleRule = ( /** @type {string | undefined} */ rule ) => { + if ( ! rule ) { + return; + } + try { + const sheet = sheetForTag(); + // this is a really hot path + // we check the second character first because having "i" + // as the second character will happen less often than + // having "@" as the first character + const isImportRule = + rule.charCodeAt( 1 ) === 105 && rule.charCodeAt( 0 ) === 64; + // this is the ultrafast version, works across browsers + // the big drawback is that the css won't be editable in devtools + sheet.insertRule( + rule, + // we need to insert @import rules before anything else + // otherwise there will be an error + // technically this means that the @import rules will + // _usually_(not always since there could be multiple style tags) + // be the first ones in prod and generally later in dev + // this shouldn't really matter in the real world though + // @import is generally only used for font faces from google fonts and etc. + // so while this could be technically correct then it would be slower and larger + // for a tiny bit of correctness that won't matter in the real world + isImportRule ? 0 : sheet.cssRules.length + ); + } catch ( e ) { + warn( + `There was a problem inserting the following rule: "${ rule }", ${ e }` + ); + } + }; + + /** + * The compiler (Emotion) has a special event emitter (pub/sub) that emits + * an event whenever the compiler sheet inserts a rule. + * + * We're subscribing to these events in order to sync the insertion from + * the primary Emotion document (window) to the Frame document. + */ + compiler.__events.on( 'sheet.insert', renderStyleRule ); + + return () => { + /** + * Unsubscribe to the events. + */ + compiler.__events.off( 'sheet.insert', renderStyleRule ); + }; + }, [ ref ] ); +} diff --git a/packages/components/src/ui/styles/core.js b/packages/components/src/ui/styles/core.js new file mode 100644 index 0000000000000..7f5ae8b116fc5 --- /dev/null +++ b/packages/components/src/ui/styles/core.js @@ -0,0 +1 @@ +export { core, get, createToken, createCoreElement, compiler } from './system'; diff --git a/packages/components/src/ui/styles/css.js b/packages/components/src/ui/styles/css.js new file mode 100644 index 0000000000000..8a428295b89c2 --- /dev/null +++ b/packages/components/src/ui/styles/css.js @@ -0,0 +1,134 @@ +/** + * External dependencies + */ +import { isPlainObject } from 'lodash'; + +/** + * Internal dependencies + */ +import { INTERPOLATION_CLASS_NAME, responsive } from '../create-styles'; +import { space } from './mixins/space'; +import { compiler } from './system'; +const { css: compile } = compiler; + +// Inspired by: +// https://github.com/system-ui/theme-ui/blob/master/packages/css/src/index.ts + +export const scales = { + gridGap: 'space', + gridColumnGap: 'space', + gridRowGap: 'space', + gap: 'space', + columnGap: 'space', + rowGap: 'space', +}; + +const transformFns = { + space, +}; + +/** + * Retrieves a scaled values from the Style system based on a style key. + * + * @param {string} key The style key to scale. + * @param {any} value The style value to scale. + * @return {any} The scaled value. + */ +export function getScaleValue( key, value ) { + const scale = scales[ /** @type {keyof scales} */ ( key ) ]; + let next = value; + + if ( scale ) { + const transformFn = + transformFns[ /** @type {keyof transformFns} */ ( scale ) ]; + if ( transformFns ) { + next = transformFn( value ); + } + } + + return next; +} + +/** + * Transform a style object with scaled values from the Style system. + * + * @param {import('@emotion/serialize').ObjectInterpolation} styles The style object to transform. + * @return {import('@emotion/serialize').ObjectInterpolation} The style object with scaled values. + */ +export function getScaleStyles( styles = {} ) { + /** @type {Record} */ + const next = {}; + + for ( const k in styles ) { + next[ k ] = getScaleValue( k, styles[ k ] ); + } + + return next; +} + +/* eslint-disable jsdoc/valid-types */ +/** + * @param {any} value + * @return {value is import('@wp-g2/create-styles').PolymorphicComponent} Whether interpolation is a PolymorphicComponent. + */ +function isPolymorphicComponent( value ) { + /* eslint-enable jsdoc/valid-types */ + return value && typeof value[ INTERPOLATION_CLASS_NAME ] !== 'undefined'; +} + +/* eslint-disable jsdoc/no-undefined-types */ +/** + * Enhances the (create-system enhanced) CSS function to account for + * scale functions within the Style system. + * + * @param {TemplateStringsArray | import('create-emotion').Interpolation} template + * @param {(import('create-emotion').Interpolation | import('@wp-g2/create-styles').PolymorphicComponent)[]} args The styles to compile. + * @return {ReturnType} The compiled styles. + */ +export function css( template, ...args ) { + /* eslint-enable jsdoc/no-undefined-types */ + if ( isPlainObject( template ) ) { + return compile( + getScaleStyles( + responsive( + /** @type {ObjectInterpolation} */ ( template ), + getScaleValue + ) + ) + ); + } + + if ( Array.isArray( template ) ) { + for ( let i = 0, len = template.length; i < len; i++ ) { + const n = template[ i ]; + + if ( isPlainObject( n ) ) { + template[ i ] = getScaleStyles( + responsive( + /** @type {ObjectInterpolation} */ ( n ), + getScaleValue + ) + ); + } + } + + const nextArgs = args.map( ( arg ) => { + if ( ! arg ) { + return arg; + } + + if ( isPolymorphicComponent( arg ) ) { + return `.${ arg[ INTERPOLATION_CLASS_NAME ] }`; + } + + return arg; + } ); + + return compile( template, ...nextArgs ); + } + + // @ts-ignore Emotion says `css` doesn't take `TemplateStringsArray` but it does! + return compile( template, ...args ); +} + +/** @typedef {import('create-emotion').ObjectInterpolation} ObjectInterpolation */ diff --git a/packages/components/src/ui/styles/hooks/index.js b/packages/components/src/ui/styles/hooks/index.js new file mode 100644 index 0000000000000..54063a0a647c4 --- /dev/null +++ b/packages/components/src/ui/styles/hooks/index.js @@ -0,0 +1,2 @@ +export * from './use-responsive-value'; +export * from './use-rtl'; diff --git a/packages/components/src/ui/styles/hooks/use-responsive-value.js b/packages/components/src/ui/styles/hooks/use-responsive-value.js new file mode 100644 index 0000000000000..baa9001b0d8e7 --- /dev/null +++ b/packages/components/src/ui/styles/hooks/use-responsive-value.js @@ -0,0 +1,88 @@ +/** + * WordPress dependencies + */ +import { useEffect, useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { breakpoints } from '../style-system'; + +/** + * @param {Node} node + * @param {Object} [options] + * @param {number} [options.defaultIndex=0] + */ +export const useBreakpointIndex = ( node, options = {} ) => { + const { defaultIndex = 0 } = options; + + if ( typeof defaultIndex !== 'number' ) { + throw new TypeError( + `Default breakpoint index should be a number. Got: ${ defaultIndex }, ${ typeof defaultIndex }` + ); + } else if ( defaultIndex < 0 || defaultIndex > breakpoints.length - 1 ) { + throw new RangeError( + `Default breakpoint index out of range. Theme has ${ breakpoints.length } breakpoints, got index ${ defaultIndex }` + ); + } + + const [ value, setValue ] = useState( defaultIndex ); + + useEffect( () => { + const getIndex = () => + breakpoints.filter( ( bp ) => { + return typeof window !== 'undefined' + ? window.matchMedia( `screen and (min-width: ${ bp })` ) + .matches + : false; + } ).length; + + const onResize = () => { + const newValue = getIndex(); + if ( value !== newValue ) { + setValue( newValue ); + } + }; + + onResize(); + + if ( node.ownerDocument ) { + node.ownerDocument.addEventListener( 'resize', onResize ); + } + return () => { + if ( node.ownerDocument ) { + node.ownerDocument.removeEventListener( 'resize', onResize ); + } + }; + }, [ value ] ); + + return value; +}; + +/* eslint-disable jsdoc/valid-types */ +/** + * @template T + * @param {Node} node + * @param {(() => (T | undefined)[]) | (T | undefined)[]} values + * @param {Parameters[1]} options + * @return {T | undefined} The responsive value for the breakpoint or the default value. + */ +export function useResponsiveValue( node, values, options = {} ) { + /* eslint-enable jsdoc/valid-types */ + const index = useBreakpointIndex( node, options ); + + // Allow calling the function with a "normal" value without having to check on the outside. + if ( ! Array.isArray( values ) && typeof values !== 'function' ) + return values; + + let array = values || []; + if ( typeof values === 'function' ) { + array = values(); + } + + /* eslint-disable jsdoc/no-undefined-types */ + return /** @type {T[]} */ ( array )[ + /* eslint-enable jsdoc/no-undefined-types */ + index >= array.length ? array.length - 1 : index + ]; +} diff --git a/packages/components/src/ui/styles/hooks/use-rtl.js b/packages/components/src/ui/styles/hooks/use-rtl.js new file mode 100644 index 0000000000000..c4acaef0aa34d --- /dev/null +++ b/packages/components/src/ui/styles/hooks/use-rtl.js @@ -0,0 +1,6 @@ +/** + * @return {boolean} Whether the current document is RTL. + */ +export function useRTL() { + return document?.documentElement?.dir === 'rtl'; +} diff --git a/packages/components/src/ui/styles/index.js b/packages/components/src/ui/styles/index.js new file mode 100644 index 0000000000000..7c4781d318933 --- /dev/null +++ b/packages/components/src/ui/styles/index.js @@ -0,0 +1,10 @@ +export * from './core'; +export { cache, css, cx, injectGlobal, keyframes } from './style-system'; + +export * from './styled'; +export * from './hooks'; +export * from './mixins'; +export * from './namespaces'; +export { config, createTheme, SUPPORTED_COLORS } from './theme'; + +export * from './components'; diff --git a/packages/components/src/ui/styles/mixins/flow.js b/packages/components/src/ui/styles/mixins/flow.js new file mode 100644 index 0000000000000..618d5ef79f6ce --- /dev/null +++ b/packages/components/src/ui/styles/mixins/flow.js @@ -0,0 +1,55 @@ +/** @typedef {number | string} FlowValue */ + +/** + * Combines CSS values. Useful for complex shorthand values, + * functions (e.g. calc()), and mixed string/JS values. + * + * @example + * ``` + * const boxShadow = flow( + * '0 1px', + * get('boxShadowSpreadValue'), + * '2px', + * get('boxShadowColor') + * ) + * ``` + * + * ##### Combining groups + * + * Groups (Array) can be passed into `flow()`, which are combined and + * comma separated. Useful for compounded CSS values (e.g. `box-shadow`). + * + * @example + * ``` + * const boxShadow = flow([ + * '0 1px', + * get('boxShadowSpreadValue'), + * '2px', + * get('boxShadowColor') + * ], [ + * '0 10px', + * get('boxShadowSpreadValue'), + * '20px', + * get('boxShadowColor') + * ] + * ) + * ``` + * + * @param {(FlowValue | FlowValue[])[]} args CSS values to combine. + * @return {string} The combined CSS string value. + */ +export function flow( ...args ) { + /** @type {FlowValue[]} */ + const results = []; + + for ( const arg of args ) { + if ( typeof arg === 'number' || typeof arg === 'string' ) { + results.push( arg ); + } + if ( Array.isArray( arg ) ) { + results.push( flow( ...arg ), ',' ); + } + } + + return results.join( ' ' ).trim().replace( /,$/, '' ); +} diff --git a/packages/components/src/ui/styles/mixins/index.js b/packages/components/src/ui/styles/mixins/index.js new file mode 100644 index 0000000000000..a3c9a6353a2b2 --- /dev/null +++ b/packages/components/src/ui/styles/mixins/index.js @@ -0,0 +1,2 @@ +export { space } from './space'; +export { flow } from './flow'; diff --git a/packages/components/src/ui/styles/mixins/space.js b/packages/components/src/ui/styles/mixins/space.js new file mode 100644 index 0000000000000..e17900a7e1558 --- /dev/null +++ b/packages/components/src/ui/styles/mixins/space.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import { get } from '../core'; + +/** + * @param {import('react').ReactText} value + * @return {string} Spacing. + */ +export function space( value ) { + return typeof value === 'number' + ? `calc(${ get( 'gridBase' ) } * ${ value })` + : value; +} diff --git a/packages/components/src/ui/styles/namespaces.js b/packages/components/src/ui/styles/namespaces.js new file mode 100644 index 0000000000000..cfe01d2c6db4a --- /dev/null +++ b/packages/components/src/ui/styles/namespaces.js @@ -0,0 +1,19 @@ +export const COMPONENT_NAMESPACE = 'data-g2-component'; + +/* eslint-disable jsdoc/valid-types */ +/** + * Creates a dedicated context namespace HTML attribute for components. + * ns is short for "namespace" + * + * @example + * ```jsx + *
+ * ``` + * + * @param {string} componentName The name for the component. + * @return {{ [COMPONENT_NAMESPACE]: string }} A props object with the namespaced HTML attribute. + */ +export function ns( componentName ) { + /* eslint-enable jsdoc/valid-types */ + return { [ COMPONENT_NAMESPACE ]: componentName }; +} diff --git a/packages/components/src/ui/styles/presets/flow.js b/packages/components/src/ui/styles/presets/flow.js new file mode 100644 index 0000000000000..ffbe577125ee7 --- /dev/null +++ b/packages/components/src/ui/styles/presets/flow.js @@ -0,0 +1,17 @@ +/** + * Internal dependencies + */ +import { flow as baseFlow } from '../mixins/flow'; + +/* eslint-disable jsdoc/valid-types */ +/** + * @type {{ + (...args: (string|string[])[]): string; + calc: (...args: (string|string[])[]) => string; +}} + */ +/* eslint-enable jsdoc/valid-types */ +// @ts-ignore We add calc below +export const flow = baseFlow; + +flow.calc = ( ...args ) => `calc(${ baseFlow( ...args ) })`; diff --git a/packages/components/src/ui/styles/style-system.js b/packages/components/src/ui/styles/style-system.js new file mode 100644 index 0000000000000..f3393db40cd58 --- /dev/null +++ b/packages/components/src/ui/styles/style-system.js @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import { compiler } from './system'; +export { css } from './css'; + +export const { + breakpoints, + cache, + cx, + flush, + getRegisteredStyles, + hydrate, + injectGlobal, + keyframes, + merge, + sheet, +} = compiler; diff --git a/packages/components/src/ui/styles/styled.js b/packages/components/src/ui/styles/styled.js new file mode 100644 index 0000000000000..62a01418baa3d --- /dev/null +++ b/packages/components/src/ui/styles/styled.js @@ -0,0 +1 @@ +export { styled } from './system'; diff --git a/packages/components/src/ui/styles/system.js b/packages/components/src/ui/styles/system.js new file mode 100644 index 0000000000000..ffaf5b11c37d9 --- /dev/null +++ b/packages/components/src/ui/styles/system.js @@ -0,0 +1,181 @@ +/** + * Internal dependencies + */ +import { createStyleSystem, get as getConfig } from '../create-styles'; +import { + config, + darkHighContrastModeConfig, + darkModeConfig, + highContrastModeConfig, +} from './theme'; + +/* eslint-disable jsdoc/valid-types */ +/** + * @typedef { + | 'colorAdmin' + | 'colorAdminRgba10' + | 'colorAdminRgba20' + | 'colorAdminRgba30' + | 'colorAdminRgba40' + | 'colorAdminRgba50' + | 'colorAdminRgba60' + | 'colorAdminRgba70' + | 'colorAdminRgba80' + | 'colorAdminRgba90' + | 'colorDestructive' + | 'colorDestructiveRgba10' + | 'colorDestructiveRgba20' + | 'colorDestructiveRgba30' + | 'colorDestructiveRgba40' + | 'colorDestructiveRgba50' + | 'colorDestructiveRgba60' + | 'colorDestructiveRgba70' + | 'colorDestructiveRgba80' + | 'colorDestructiveRgba90' + | 'gray100Text' + | 'gray300Text' + | 'gray500Text' + | 'gray700Text' + | 'gray900Text' + | 'darkGray100Text' + | 'darkGray300Text' + | 'darkGray500Text' + | 'darkGray700Text' + | 'darkGray900Text' + | 'red100Text' + | 'red300Text' + | 'red500Text' + | 'red700Text' + | 'red900Text' + | 'orange100Text' + | 'orange300Text' + | 'orange500Text' + | 'orange700Text' + | 'orange900Text' + | 'yellow100Text' + | 'yellow300Text' + | 'yellow500Text' + | 'yellow700Text' + | 'yellow900Text' + | 'green100Text' + | 'green300Text' + | 'green500Text' + | 'green700Text' + | 'green900Text' + | 'purple100Text' + | 'purple300Text' + | 'purple500Text' + | 'purple700Text' + | 'purple900Text' + | 'purple100Text' + | 'purple300Text' + | 'purple500Text' + | 'purple700Text' + | 'purple900Text' + | 'grayRgba10' + | 'grayRgba20' + | 'grayRgba30' + | 'grayRgba40' + | 'grayRgba50' + | 'grayRgba60' + | 'grayRgba70' + | 'grayRgba80' + | 'grayRgba90' + | 'darkGrayRgba10' + | 'darkGrayRgba20' + | 'darkGrayRgba30' + | 'darkGrayRgba40' + | 'darkGrayRgba50' + | 'darkGrayRgba60' + | 'darkGrayRgba70' + | 'darkGrayRgba80' + | 'darkGrayRgba90' + | 'redRgba10' + | 'redRgba20' + | 'redRgba30' + | 'redRgba40' + | 'redRgba50' + | 'redRgba60' + | 'redRgba70' + | 'redRgba80' + | 'redRgba90' + | 'orangeRgba10' + | 'orangeRgba20' + | 'orangeRgba30' + | 'orangeRgba40' + | 'orangeRgba50' + | 'orangeRgba60' + | 'orangeRgba70' + | 'orangeRgba80' + | 'orangeRgba90' + | 'yellowRgba10' + | 'yellowRgba20' + | 'yellowRgba30' + | 'yellowRgba40' + | 'yellowRgba50' + | 'yellowRgba60' + | 'yellowRgba70' + | 'yellowRgba80' + | 'yellowRgba90' + | 'greenRgba10' + | 'greenRgba20' + | 'greenRgba30' + | 'greenRgba40' + | 'greenRgba50' + | 'greenRgba60' + | 'greenRgba70' + | 'greenRgba80' + | 'greenRgba90' + | 'purpleRgba10' + | 'purpleRgba20' + | 'purpleRgba30' + | 'purpleRgba40' + | 'purpleRgba50' + | 'purpleRgba60' + | 'purpleRgba70' + | 'purpleRgba80' + | 'purpleRgba90' + | 'blueRgba10' + | 'blueRgba20' + | 'blueRgba30' + | 'blueRgba40' + | 'blueRgba50' + | 'blueRgba60' + | 'blueRgba70' + | 'blueRgba80' + | 'blueRgba90' + + // Theme tokens that pop up throughout the codebase + | 'flexGap' + | 'flexItemDisplay' + | 'surfaceBackgroundSize' + | 'surfaceBackgroundSizeDotted' +} GeneratedDesignTokens + */ +/* eslint-enable jsdoc/valid-types */ + +/** @type {import('../create-styles').CreateStyleSystemOptions} */ +const systemConfig = { + baseStyles: { + MozOsxFontSmoothing: 'grayscale', + WebkitFontSmoothing: 'antialiased', + fontFamily: getConfig( 'fontFamily' ), + fontSize: getConfig( 'fontSize' ), + // @ts-ignore + fontWeight: getConfig( 'fontWeight' ), + margin: 0, + }, + config, + darkModeConfig, + highContrastModeConfig, + darkHighContrastModeConfig, +}; + +export const { + compiler, + core, + createCoreElement, + createToken, + get, + styled, +} = createStyleSystem( systemConfig ); diff --git a/packages/components/src/ui/styles/test/component-interpolation.js b/packages/components/src/ui/styles/test/component-interpolation.js new file mode 100644 index 0000000000000..6802156385de0 --- /dev/null +++ b/packages/components/src/ui/styles/test/component-interpolation.js @@ -0,0 +1,161 @@ +/** + * External dependencies + */ +import { render } from '@testing-library/react'; +import { contextConnect, useContextSystem } from '@wp-g2/context'; + +/** + * WordPress dependencies + */ +import { forwardRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { css, styled } from '..'; + +describe( 'component-interpolation', () => { + const getLastAppliedCssRule = () => { + const styles = document.getElementsByTagName( 'style' ); + const lastSheet = Array.from( styles ).slice( -1 )[ 0 ]; + const rules = Array.from( lastSheet.sheet.cssRules ); + return rules.slice( -1 )[ 0 ]; + }; + + beforeEach( () => { + // clean up generated styles and elements + document.head.innerHTML = ''; + } ); + + it( 'should interpolate styled components from core components', () => { + const StyledA = styled.div` + background-color: blue; + `; + + const classes = css` + color: red; + ${ StyledA } { + color: blue; + } + `; + + const rule = getLastAppliedCssRule(); + + const { container } = render( +
+ +
+ ); + const styledA = container.firstChild.firstChild; + + expect( styledA.matches( rule.selectorText ) ).toBe( true ); + } ); + + it( 'should interpolate styled components', () => { + const Component = forwardRef( ( { className }, ref ) => ( +
+ ) ); + const StyledComponent = styled( Component )``; + + const classes = css` + color: red; + ${ StyledComponent } { + color: blue; + } + `; + + const rule = getLastAppliedCssRule(); + + const { container } = render( +
+ +
+ ); + const styledComponent = container.firstChild.firstChild; + expect( styledComponent.matches( rule.selectorText ) ).toBe( true ); + } ); + + it( 'should interpolate styled components inside of styled component styles', () => { + const StyledA = styled.div``; + const StyledB = styled.div` + ${ StyledA } { + color: blue; + } + `; + + const { container } = render( + + + + ); + const rule = getLastAppliedCssRule(); + + const styledA = container.firstChild.firstChild; + expect( styledA.matches( rule.selectorText ) ).toBe( true ); + } ); + + it( 'should interpolate context-connected components', () => { + const TestConnectedStyledComponent = ( props, forwardedRef ) => { + const connectedProps = useContextSystem( + props, + 'TestConnectedStyledComponent' + ); + return
; + }; + + const Connected = contextConnect( + TestConnectedStyledComponent, + 'TestConnectedStyledComponent' + ); + + const classes = css` + color: red; + ${ Connected } { + color: blue; + } + `; + + const rule = getLastAppliedCssRule(); + + const { container } = render( +
+ +
+ ); + + const connected = container.firstChild.firstChild; + expect( connected.matches( rule.selectorText ) ).toBe( true ); + } ); + + it( 'should interpolate context-connected-components in styled', () => { + const TestConnectedStyledComponent = ( props, forwardedRef ) => { + const connectedProps = useContextSystem( + props, + 'TestConnectedStyledComponent' + ); + return
; + }; + + const Connected = contextConnect( + TestConnectedStyledComponent, + 'TestConnectedStyledComponent' + ); + + const Container = styled.div` + color: red; + ${ Connected } { + color: blue; + } + `; + + const { container } = render( + + + + ); + const rule = getLastAppliedCssRule(); + + const connected = container.firstChild.firstChild; + expect( connected.matches( rule.selectorText ) ).toBe( true ); + } ); +} ); diff --git a/packages/components/src/ui/styles/test/css.js b/packages/components/src/ui/styles/test/css.js index 593bb40b3a91a..858e83343d08e 100644 --- a/packages/components/src/ui/styles/test/css.js +++ b/packages/components/src/ui/styles/test/css.js @@ -1,9 +1,13 @@ /** * External dependencies */ -import { css } from '@wp-g2/styles'; import { render } from '@testing-library/react'; +/** + * Internal dependencies + */ +import { css } from '..'; + describe( 'basic', () => { test( 'should return a string', () => { const style = css` @@ -82,34 +86,4 @@ describe( 'plugins', () => { expect( container.firstChild ).toHaveStyle( `background: blue;` ); } ); - - test( 'should automatically render rtl styles', () => { - // Simulate an rtl environment - document.documentElement.setAttribute( 'dir', 'rtl' ); - // Create the style - const style = css` - padding-right: 55px; - margin-right: 55px; - right: 55px; - transform: translateX( 55% ); - `; - - const { container } = render(
); - - expect( container.firstChild ).toHaveStyle( `margin-left: 55px;` ); - expect( container.firstChild ).toHaveStyle( `padding-left: 55px;` ); - expect( container.firstChild ).toHaveStyle( `left: 55px;` ); - expect( container.firstChild ).toHaveStyle( - `transform: translateX( -55% );` - ); - - expect( container.firstChild ).not.toHaveStyle( `margin-right: 55px;` ); - expect( container.firstChild ).not.toHaveStyle( - `padding-right: 55px;` - ); - expect( container.firstChild ).not.toHaveStyle( `right: 55px;` ); - expect( container.firstChild ).not.toHaveStyle( - `transform: translateX( 55% );` - ); - } ); } ); diff --git a/packages/components/src/ui/styles/test/scales.js b/packages/components/src/ui/styles/test/scales.js new file mode 100644 index 0000000000000..1446f45ceb544 --- /dev/null +++ b/packages/components/src/ui/styles/test/scales.js @@ -0,0 +1,49 @@ +/** + * Internal dependencies + */ +import { space } from '..'; +import { getScaleStyles } from '../css'; + +describe( 'scales', () => { + test( 'should transform space values', () => { + const numberValues = { + gridGap: 4, + gridColumnGap: 4, + gridRowGap: 4, + gap: 4, + columnGap: 4, + rowGap: 4, + }; + + for ( const key in numberValues ) { + const value = numberValues[ key ]; + const assert = {}; + const result = {}; + + assert[ key ] = value; + result[ key ] = space( value ); + + expect( getScaleStyles( assert ) ).toEqual( result ); + } + + const stringValues = { + gridGap: '6px', + gridColumnGap: '6px', + gridRowGap: '6px', + gap: '6px', + columnGap: '6px', + rowGap: '6px', + }; + + for ( const key in stringValues ) { + const value = stringValues[ key ]; + const assert = {}; + const result = {}; + + assert[ key ] = value; + result[ key ] = space( value ); + + expect( getScaleStyles( assert ) ).toEqual( result ); + } + } ); +} ); diff --git a/packages/components/src/ui/styles/test/styled.js b/packages/components/src/ui/styles/test/styled.js index 271b32ad97c1f..9ed9feb58f73b 100644 --- a/packages/components/src/ui/styles/test/styled.js +++ b/packages/components/src/ui/styles/test/styled.js @@ -1,9 +1,18 @@ /** * External dependencies */ -import { css, styled } from '@wp-g2/styles'; import { render } from '@testing-library/react'; +/** + * WordPress dependencies + */ +import { forwardRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { css, styled } from '..'; + describe( 'basic', () => { test( 'should create a styled component', () => { const Component = styled.div` @@ -16,7 +25,9 @@ describe( 'basic', () => { } ); test( 'should style an existing component', () => { - const Previous = ( { className } ) =>
; + const Previous = forwardRef( ( { className }, ref ) => ( +
+ ) ); const Component = styled( Previous )` background: blue; @@ -57,34 +68,6 @@ describe( 'css', () => { expect( container.firstChild ).toHaveStyle( { background: 'blue' } ); expect( container.firstChild ).toHaveStyle( { color: 'red' } ); } ); - - test( 'should render styles with css prop (string)', () => { - const Component = styled.div` - background: blue; - `; - - const { container } = render( - - ); - - expect( container.firstChild ).toHaveStyle( { background: 'blue' } ); - expect( container.firstChild ).toHaveStyle( { color: 'red' } ); - } ); - - test( 'should render styles with css prop (object)', () => { - const Component = styled.div` - background: blue; - `; - - const { container } = render( ); - - expect( container.firstChild ).toHaveStyle( { background: 'blue' } ); - expect( container.firstChild ).toHaveStyle( { color: 'red' } ); - } ); } ); describe( 'as', () => { diff --git a/packages/components/src/ui/styles/theme/config.js b/packages/components/src/ui/styles/theme/config.js new file mode 100644 index 0000000000000..4aa3ba69ec0a5 --- /dev/null +++ b/packages/components/src/ui/styles/theme/config.js @@ -0,0 +1,370 @@ +/** + * Internal dependencies + */ +import { get } from '../../create-styles'; +import { flow } from '../presets/flow'; +import { BACKGROUND_COLOR_PROPS, G2_COLORS, WORDPRESS_COLORS } from './tokens'; +import { + generateColorAdminColors, + generateColorDestructiveColors, + space, +} from './utils'; + +export const SUPPORTED_COLORS = [ + 'blue', + 'red', + 'purple', + 'green', + 'yellow', + 'orange', + 'darkGray', + 'lightGray', +]; + +const ANIMATION_PROPS = { + transitionDuration: '200ms', + transitionDurationFast: '160ms', + transitionDurationFaster: '120ms', + transitionDurationFastest: '100ms', + transitionTimingFunction: 'cubic-bezier(0.08, 0.52, 0.52, 1)', + transitionTimingFunctionControl: 'cubic-bezier(0.12, 0.8, 0.32, 1)', +}; + +const COLOR_PROPS = { + ...WORDPRESS_COLORS, + ...BACKGROUND_COLOR_PROPS, + colorAdmin: '#007cba', + colorDestructive: '#D94F4F', + colorBodyBackground: get( 'white' ), + colorDivider: 'rgba(0, 0, 0, 0.1)', + colorPositive: get( 'greens' ), + colorScrollbarThumb: 'rgba(0, 0, 0, 0.2)', + colorScrollbarThumbHover: 'rgba(0, 0, 0, 0.5)', + colorScrollbarTrack: 'rgba(0, 0, 0, 0.04)', + colorText: '#1e1e1e', + colorTextInverted: get( 'white' ), + colorTextHeading: '#050505', + colorTextMuted: '#717171', + ...generateColorAdminColors( '#007cba' ), + ...generateColorDestructiveColors( '#D94F4F' ), +}; + +const FONT_PROPS = { + fontFamily: + 'Inter,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",sans-serif', + fontFamilyMono: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace', + fontSize: '13px', + fontSizeH1: `calc(2.44 * ${ get( 'fontSize' ) })`, + fontSizeH2: `calc(1.95 * ${ get( 'fontSize' ) })`, + fontSizeH3: `calc(1.56 * ${ get( 'fontSize' ) })`, + fontSizeH4: `calc(1.25 * ${ get( 'fontSize' ) })`, + fontSizeH5: `calc(1 * ${ get( 'fontSize' ) })`, + fontSizeH6: `calc(0.8 * ${ get( 'fontSize' ) })`, + fontSizeInputMobile: '16px', + fontSizeMobile: '15px', + fontSizeSmall: `calc(0.92 * ${ get( 'fontSize' ) })`, + fontSizeXSmall: `calc(0.75 * ${ get( 'fontSize' ) })`, + fontLineHeightBase: '1.2', + fontWeight: 'normal', + fontWeightHeading: '600', +}; + +const SURFACE_PROPS = { + surfaceBackgroundColor: get( 'surfaceColor' ), + surfaceBackgroundSubtleColor: '#F3F3F3', + surfaceBackgroundTintColor: '#F5F5F5', + surfaceBorderColor: 'rgba(0, 0, 0, 0.1)', + surfaceBorderBoldColor: 'rgba(0, 0, 0, 0.15)', + surfaceBorderSubtleColor: 'rgba(0, 0, 0, 0.05)', + surfaceBackgroundTertiaryColor: '#ffffff', + surfaceColor: get( 'white' ), +}; + +const ELEVATION_PROPS = { + elevationIntensity: 1, +}; + +const GRID_PROPS = { + gridBase: '4px', +}; + +const CONTROL_PROPS = { + controlBackgroundColor: get( 'white' ), + controlBackgroundColorHover: 'rgba(0, 0, 0, 0.05)', + controlBackgroundColorActive: 'rgba(0, 0, 0, 0.05)', + controlBackgroundDimColor: 'rgba(0, 0, 0, 0.1)', + controlBackgroundBrightColor: 'rgba(0, 0, 0, 0.03)', + controlBorderColor: '#757575', + controlBorderColorHover: get( 'controlBorderColor' ), + controlBorderColorSubtle: 'transparent', + controlBorderRadius: '2px', + controlBorderSubtleColor: 'rgba(0, 0, 0, 0.2)', + controlBoxShadowFocusSize: '0.5px', + controlBoxShadow: `transparent`, + controlBoxShadowFocus: flow( + '0 0 0', + get( 'controlBoxShadowFocusSize' ), + get( 'colorAdmin' ) + ), + controlPseudoBoxShadowFocusWidth: '2px', + controlPseudoBoxShadowFocusRingSize: flow.calc( + get( 'controlPseudoBoxShadowFocusWidth' ), + '+ 1px +', + get( 'controlBoxShadowFocusSize' ) + ), + controlPseudoBoxShadowFocusRingSizeSmall: flow.calc( + get( 'controlPseudoBoxShadowFocusWidth' ), + '+ 1px' + ), + controlPseudoBoxShadowFocus: flow( + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusWidth' ), + get( 'surfaceBackgroundColor' ), + ], + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusRingSize' ), + get( 'colorAdmin' ), + ] + ), + controlPseudoBoxShadowFocusSmall: flow( + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusWidth' ), + get( 'surfaceBackgroundColor' ), + ], + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusRingSizeSmall' ), + get( 'colorAdmin' ), + ] + ), + controlDestructivePseudoBoxShadowFocus: flow( + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusWidth' ), + get( 'surfaceBackgroundColor' ), + ], + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusRingSize' ), + get( 'colorDestructive' ), + ] + ), + controlDestructivePseudoBoxShadowFocusSmall: flow( + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusWidth' ), + get( 'surfaceBackgroundColor' ), + ], + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusRingSizeSmall' ), + get( 'colorDestructive' ), + ] + ), + controlDestructiveBorderColor: get( 'colorDestructive' ), + controlDestructiveBorderColorFocus: get( 'controlDestructiveBorderColor' ), + controlDestructiveBoxShadowFocus: flow( + '0 0 0', + get( 'controlBoxShadowFocusSize' ), + get( 'colorDestructive' ) + ), + controlHeight: '30px', + controlHeightLarge: `calc(${ get( 'controlHeight' ) } * 1.2)`, + controlHeightSmall: `calc(${ get( 'controlHeight' ) } * 0.8)`, + controlHeightXLarge: `calc(${ get( 'controlHeight' ) } * 1.4)`, + controlHeightXSmall: `calc(${ get( 'controlHeight' ) } * 0.67)`, + controlHeightXXSmall: `calc(${ get( 'controlHeight' ) } * 0.4)`, + controlPaddingX: '12px', + controlPaddingXLarge: `calc(${ get( 'controlPaddingX' ) } * 1.3334)`, + controlPaddingXSmall: `calc(${ get( 'controlPaddingX' ) } / 1.3334)`, + controlPrimaryTextColorActive: get( 'white' ), + controlPrimaryTextColor: get( 'white' ), + controlSurfaceBoxShadow: flow( + [ '0 1px 1px rgba(0, 0, 0, 0.2)' ], + [ '0 1px 2px rgba(0, 0, 0, 0.2)' ] + ), + controlSurfaceColor: get( 'white' ), + controlTextActiveColor: get( 'colorAdmin' ), + controlInnerControltextColor: get( 'colorAdmin' ), +}; + +const BUTTON_PROPS = { + buttonPaddingXRatio: 'calc(4/3)', + buttonPaddingX: flow.calc( + get( 'controlPaddingX' ), + '*', + get( 'buttonPaddingXRatio' ) + ), + + buttonTextColor: get( 'colorAdmin' ), + buttonTextColorActive: get( 'buttonTextColor' ), + + buttonPrimaryColor: get( 'colorAdmin' ), + buttonPrimaryColorHover: get( 'buttonPrimaryColor' ), + buttonPrimaryColorActive: get( 'colorText' ), + buttonPrimaryColorFocus: get( 'buttonPrimaryColor' ), + buttonPrimaryBorderColor: get( 'buttonPrimaryColor' ), + buttonPrimaryBorderColorHover: get( 'buttonPrimaryColor' ), + buttonPrimaryBorderColorFocus: get( 'buttonPrimaryColor' ), + buttonPrimaryBorderColorActive: get( 'buttonPrimaryColor' ), + buttonPrimaryTextColor: get( 'controlPrimaryTextColor' ), + buttonPrimaryTextColorHover: get( 'controlPrimaryTextColor' ), + buttonPrimaryTextColorActive: get( 'controlPrimaryTextColor' ), + buttonPrimaryTextColorFocus: get( 'controlPrimaryTextColor' ), + + buttonSecondaryColor: 'transparent', + buttonSecondaryColorHover: get( 'buttonSecondaryColor' ), + buttonSecondaryColorActive: 'rgba(0, 0, 0, 0.05)', + buttonSecondaryColorFocus: get( 'buttonSecondaryColor' ), + buttonSecondaryBorderColor: get( 'buttonPrimaryColor' ), + buttonSecondaryTextColor: get( 'buttonPrimaryColor' ), + buttonSecondaryTextColorFocus: get( 'buttonPrimaryColor' ), + buttonSecondaryTextColorActive: get( 'buttonPrimaryColor' ), + buttonSecondaryBorderColorHover: get( 'buttonPrimaryColor' ), + buttonSecondaryBorderColorActive: get( 'buttonPrimaryColor' ), + buttonSecondaryBorderColorFocus: get( 'buttonPrimaryColor' ), + + buttonTertiaryColor: 'transparent', + buttonTertiaryColorHover: get( 'buttonTertiaryColor' ), + buttonTertiaryColorActive: 'rgba(0, 0, 0, 0.05)', + buttonTertiaryColorFocus: get( 'buttonTertiaryColor' ), + buttonTertiaryBorderColor: 'transparent', + buttonTertiaryTextColor: get( 'buttonPrimaryColor' ), + buttonTertiaryTextColorFocus: get( 'buttonPrimaryColor' ), + buttonTertiaryTextColorActive: get( 'buttonPrimaryColor' ), + buttonTertiaryBorderColorHover: get( 'buttonPrimaryColor' ), + buttonTertiaryBorderColorActive: get( 'buttonPrimaryColor' ), + buttonTertiaryBorderColorFocus: get( 'buttonPrimaryColor' ), + + buttonControlActiveStateColor: get( 'colorText' ), + buttonControlActiveStateColorHover: get( 'buttonControlActiveStateColor' ), + buttonControlActiveStateColorActive: get( 'buttonControlActiveStateColor' ), + buttonControlActiveStateColorFocus: get( 'buttonControlActiveStateColor' ), + buttonControlActiveStateTextColor: get( 'buttonPrimaryTextColor' ), + buttonControlActiveStateBorderColorFocus: get( 'buttonPrimaryColor' ), + buttonControlActiveStateBoxShadowFocus: flow( + [ '0 0 0', get( 'controlBoxShadowFocusSize' ), get( 'colorAdmin' ) ], + [ + '0 0 0', + get( 'controlPseudoBoxShadowFocusWidth' ), + get( 'buttonControlActiveStateTextColor' ), + 'inset', + ] + ), +}; + +const CARD_PROPS = { + cardBorderRadius: '2px', + cardPaddingX: space( 3 ), + cardPaddingY: space( 3 ), + cardPadding: flow( get( 'cardPaddingX' ), get( 'cardPaddingY' ) ), + cardHeaderFooterPaddingY: space( 1 ), + cardHeaderHeight: '44px', +}; + +const CHECKBOX_PROPS = { + checkboxBoxShadow: 'none', + checkboxSize: '16px', +}; + +const FLEX_PROPS = { + flexGap: space( 2 ), + flexItemMarginRight: get( 'flexGap' ), +}; + +const LINK_PROPS = { + linkColor: get( 'colorAdmin' ), + linkColorHover: get( 'colorAdmin' ), + linkColorActive: get( 'colorAdmin' ), + linkColorFocus: get( 'colorAdmin' ), +}; + +const MENU_PROPS = { + menuItemBorderWidth: '1px', + menuItemFocusBackgroundColor: 'transparent', + menuItemFocusBorderColor: get( 'colorAdmin' ), + menuItemFocusTextColor: get( 'menuItemFocusBorderColor' ), + menuItemFocusBoxShadow: get( 'controlBorderSubtleColor' ), + menuItemActiveBackgroundColor: get( 'controlBackgroundColor' ), + menuItemActiveBorderColor: get( 'menuItemFocusBorderColor' ), + menuItemActiveTextColor: get( 'colorText' ), + menuItemActiveBoxShadow: get( 'controlBorderSubtleColor' ), + menuItemHeight: '30px', + menuItemHeightLarge: `calc(${ get( 'menuItemHeight' ) } * 1.2)`, + menuItemHeightSmall: `calc(${ get( 'menuItemHeight' ) } * 0.8)`, + menuItemHeightXLarge: `calc(${ get( 'menuItemHeight' ) } * 1.4)`, + menuItemHeightXSmall: `calc(${ get( 'menuItemHeight' ) } * 0.67)`, + menuItemHeightXXSmall: `calc(${ get( 'menuItemHeight' ) } * 0.4)`, +}; + +const PANEL_PROPS = { + panelHeaderPadding: `${ space( 3 ) } ${ space( 4 ) }`, + panelBodyPadding: `${ space( 2 ) } ${ space( 4 ) } ${ space( 3 ) }`, +}; + +const RADIO_PROPS = { + radioBoxShadow: get( 'checkboxBoxShadow' ), + radioSize: get( 'checkboxSize' ), + radioDotSize: '10px', +}; + +const SEGMENTED_CONTROL_PROPS = { + segmentedControlFontSize: '12px', + segmentedControlBackgroundColor: get( 'controlBackgroundColor' ), + segmentedControlBorderColor: get( 'controlBorderColor' ), + segmentedControlBackdropBackgroundColor: get( 'controlSurfaceColor' ), + segmentedControlBackdropBorderColor: get( 'controlBorderColor' ), + segmentedControlBackdropBoxShadow: 'transparent', + segmentedControlButtonColorActive: get( 'controlBackgroundColor' ), +}; + +const SLIDER_PROPS = { + sliderThumbBorderColor: 'transparent', + sliderThumbBoxShadow: 'none', + sliderThumbBoxShadowSizeFocus: '3px', + sliderThumbBoxShadowColorFocus: get( 'colorAdminRgba20' ), + sliderThumbBackgroundColor: get( 'colorAdmin' ), +}; + +const SWITCH_PROPS = { + switchBackdropBackgroundColor: get( 'lightGray900' ), + switchBackdropBackgroundColorActive: get( 'colorAdmin' ), + switchBackdropBorderColor: get( 'lightGray900' ), + switchBackdropBorderColorActive: get( 'colorAdmin' ), + switchBackdropBorderColorFocus: get( 'white' ), + switchToggleBackgroundColor: get( 'colorTextInverted' ), + switchToggleBackgroundColorActive: get( 'colorTextInverted' ), + switchToggleBoxShadow: 'none', + switchPaddingOffset: '6px', +}; + +const BASE_THEME = { + // Colors + ...G2_COLORS, + ...COLOR_PROPS, + // Base + ...CARD_PROPS, + ...CONTROL_PROPS, + ...ELEVATION_PROPS, + ...FLEX_PROPS, + ...FONT_PROPS, + ...SURFACE_PROPS, + // Animations + ...ANIMATION_PROPS, + // The Rest + ...BUTTON_PROPS, + ...CHECKBOX_PROPS, + ...GRID_PROPS, + ...LINK_PROPS, + ...MENU_PROPS, + ...PANEL_PROPS, + ...RADIO_PROPS, + ...SEGMENTED_CONTROL_PROPS, + ...SLIDER_PROPS, + ...SWITCH_PROPS, +}; + +export const config = BASE_THEME; diff --git a/packages/components/src/ui/styles/theme/create-theme.js b/packages/components/src/ui/styles/theme/create-theme.js new file mode 100644 index 0000000000000..5b60d19f0dff2 --- /dev/null +++ b/packages/components/src/ui/styles/theme/create-theme.js @@ -0,0 +1,44 @@ +/** + * External dependencies + */ +import colorize from 'tinycolor2'; + +/** + * Internal dependencies + */ +import { get } from '../../create-styles'; +import { space } from '../mixins/space'; +import { config } from './config'; +import { generateColorAdminColors } from './utils'; +import { getComputedColor } from '../../utils/colors'; + +const baseTheme = Object.freeze( Object.assign( {}, config ) ); + +/* eslint-disable jsdoc/valid-types */ +/** + * @param {(props: { get: typeof get, theme: typeof baseTheme, color: typeof colorize, space: typeof space }) => Record} callback + * @return {Record} The theme. + */ +export function createTheme( callback ) { + /* eslint-enable jsdoc/valid-types */ + const props = { + get, + theme: baseTheme, + color: colorize, + space, + }; + + const customConfig = callback( props ); + + let colorAdminColors = {}; + + if ( customConfig.colorAdmin ) { + const colorAdminValue = getComputedColor( customConfig.colorAdmin ); + colorAdminColors = generateColorAdminColors( colorAdminValue ); + } + + return { + ...customConfig, + ...colorAdminColors, + }; +} diff --git a/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js b/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js new file mode 100644 index 0000000000000..8ffcc7aa98260 --- /dev/null +++ b/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js @@ -0,0 +1,7 @@ +export const darkHighContrastModeConfig = { + colorDivider: '#eee', + controlBorderColor: '#eee', + controlBorderColorHover: '#eee', + controlBorderColorSubtle: '#eee', + surfaceBorderColor: '#eee', +}; diff --git a/packages/components/src/ui/styles/theme/dark-mode-config.js b/packages/components/src/ui/styles/theme/dark-mode-config.js new file mode 100644 index 0000000000000..72778f9b70ece --- /dev/null +++ b/packages/components/src/ui/styles/theme/dark-mode-config.js @@ -0,0 +1,44 @@ +/** + * Internal dependencies + */ +import { get } from '../../create-styles'; +import { DARK_MODE_COLORS, DARK_MODE_RGBA_COLORS } from './tokens'; + +const DARK_MODE_PROPS = { + ...DARK_MODE_COLORS, + ...DARK_MODE_RGBA_COLORS, + buttonPrimaryTextColorActive: get( 'controlPrimaryTextColorActive' ), + buttonControlActiveStateTextColor: get( 'colorTextInverted' ), + colorBodyBackground: '#18191A', + colorDivider: 'rgba(255, 255, 255, 0.1)', + colorScrollbarThumb: 'rgba(255, 255, 255, 0.2)', + colorScrollbarThumbHover: 'rgba(255, 255, 255, 0.5)', + colorScrollbarTrack: 'rgba(0, 0, 0, 0.04)', + colorText: '#E4E6EB', + colorTextMuted: '#7a7a7a', + colorTextInverted: '#050505', + colorTextHeading: '#ffffff', + controlBackgroundColor: get( 'colorBodyBackground' ), + controlBackgroundColorHover: 'rgba(255, 255, 255, 0.3)', + controlBackgroundBrightColor: 'rgba(255, 255, 255, 0.08)', + controlBackgroundDimColor: 'rgba(255, 255, 255, 0.2)', + controlBorderSubtleColor: 'rgba(255, 255, 255, 0.5)', + controlPrimaryTextColorActive: get( 'black' ), + controlPrimaryTextColor: get( 'white' ), + controlSurfaceColor: 'rgba(255, 255, 255, 0.3)', + controlTextActiveColor: get( 'white' ), + surfaceBackgroundColor: get( 'colorBodyBackground' ), + surfaceBackgroundSubtleColor: '#151515', + surfaceBackgroundTintColor: '#252525', + surfaceBackgroundTertiaryColor: '#000', + surfaceBorderColor: 'rgba(255, 255, 255, 0.1)', + surfaceBorderBoldColor: 'rgba(255, 255, 255, 0.15)', + surfaceBorderSubtleColor: 'rgba(255, 255, 255, 0.05)', + surfaceColor: '#292929', +}; + +export const DARK_THEME = { + ...DARK_MODE_PROPS, +}; + +export const darkModeConfig = DARK_THEME; diff --git a/packages/components/src/ui/styles/theme/high-contrast-mode-config.js b/packages/components/src/ui/styles/theme/high-contrast-mode-config.js new file mode 100644 index 0000000000000..d47dd17009b17 --- /dev/null +++ b/packages/components/src/ui/styles/theme/high-contrast-mode-config.js @@ -0,0 +1,7 @@ +export const highContrastModeConfig = { + colorDivider: '#444', + controlBorderColor: '#444', + controlBorderColorHover: '#444', + controlBorderColorSubtle: '#444', + surfaceBorderColor: '#444', +}; diff --git a/packages/components/src/ui/styles/theme/index.js b/packages/components/src/ui/styles/theme/index.js new file mode 100644 index 0000000000000..5bf265f14f643 --- /dev/null +++ b/packages/components/src/ui/styles/theme/index.js @@ -0,0 +1,2 @@ +export * from './create-theme'; +export * from './theme'; diff --git a/packages/components/src/ui/styles/theme/theme.js b/packages/components/src/ui/styles/theme/theme.js new file mode 100644 index 0000000000000..5851aeacfa1ee --- /dev/null +++ b/packages/components/src/ui/styles/theme/theme.js @@ -0,0 +1,31 @@ +export { config } from './config'; +export { darkModeConfig } from './dark-mode-config'; +export { highContrastModeConfig } from './high-contrast-mode-config'; +export { darkHighContrastModeConfig } from './dark-high-contrast-mode-config'; + +/* eslint-disable jsdoc/valid-types */ +/** + * @typedef { + | 'blue' + | 'red' + | 'purple' + | 'green' + | 'yellow' + | 'orange' + | 'darkGray' + | 'lightGray' + } SupportedColors + */ +/* eslint-enable jsdoc/valid-types */ + +/** @type {SupportedColors[]} */ +export const SUPPORTED_COLORS = [ + 'blue', + 'red', + 'purple', + 'green', + 'yellow', + 'orange', + 'darkGray', + 'lightGray', +]; diff --git a/packages/components/src/ui/styles/theme/tokens/colors.js b/packages/components/src/ui/styles/theme/tokens/colors.js new file mode 100644 index 0000000000000..9c996cdaa95cf --- /dev/null +++ b/packages/components/src/ui/styles/theme/tokens/colors.js @@ -0,0 +1,206 @@ +/** + * Internal dependencies + */ +import { get } from '../../../create-styles'; +import { createRgbaColors, createTextColors } from '../utils'; + +export const CORE_PURPLE_COLORS = { + purple100: '#f3f1f8', + purple300: '#B4A8D2', + purple500: '#826eb4', + purple700: '#4e426c', + purple900: '#342c48', +}; + +export const CORE_DARK_GRAY_COLORS = { + darkGray100: '#8F98A1', + darkGray300: '#6C7781', + darkGray500: '#555D66', + darkGray700: '#32373C', + darkGray900: '#191E23', +}; + +export const CORE_LIGHT_GRAY_COLORS = { + lightGray100: '#fbfbfc', + lightGray300: '#edeff0', + lightGray500: '#e2e4e7', + lightGray700: '#ccd0d4', + lightGray900: '#a2aab2', +}; + +export const CORE_RED_COLORS = { + red100: '#fcebeb', + red300: '#ea8484', + red500: '#dc3232', + red700: '#b02828', + red900: '#841e1e', +}; + +export const CORE_ORANGE_COLORS = { + orange100: '#fef1ea', + orange300: '#f9a87e', + orange500: '#F56E28', + orange700: '#ca4a1f', + orange900: '#aa3e1a', +}; + +export const CORE_YELLOW_COLORS = { + yellow100: '#fff8e6', + yellow300: '#ffd566', + yellow500: '#ffb900', + yellow700: '#ee8e0d', + yellow900: '#dd631a', +}; + +export const CORE_GREEN_COLORS = { + green100: '#edf8ee', + green300: '#90d296', + green500: '#46b450', + green700: '#328540', + green900: '#25612f', +}; + +export const CORE_BLUE_COLORS = { + blue100: '#e6f6fb', + blue300: '#66c6e4', + blue500: '#00a0d2', + blue700: '#0085ba', + blue900: '#0072A8', +}; + +export const DARK_GRAY_COLORS = { + ...CORE_DARK_GRAY_COLORS, + ...createTextColors( CORE_DARK_GRAY_COLORS ), + ...createRgbaColors( CORE_DARK_GRAY_COLORS ), +}; + +export const LIGHT_GRAY_COLORS = { + ...CORE_LIGHT_GRAY_COLORS, + ...createTextColors( CORE_LIGHT_GRAY_COLORS ), + ...createRgbaColors( CORE_LIGHT_GRAY_COLORS ), +}; + +export const RED_COLORS = { + ...CORE_RED_COLORS, + ...createTextColors( CORE_RED_COLORS ), + ...createRgbaColors( CORE_RED_COLORS ), +}; + +export const ORANGE_COLORS = { + ...CORE_ORANGE_COLORS, + ...createTextColors( CORE_ORANGE_COLORS ), + ...createRgbaColors( CORE_ORANGE_COLORS ), +}; + +export const YELLOW_COLORS = { + ...CORE_YELLOW_COLORS, + ...createTextColors( CORE_YELLOW_COLORS ), + ...createRgbaColors( CORE_YELLOW_COLORS ), +}; + +export const GREEN_COLORS = { + ...CORE_GREEN_COLORS, + ...createTextColors( CORE_GREEN_COLORS ), + ...createRgbaColors( CORE_GREEN_COLORS ), +}; + +export const PURPLE_COLORS = { + ...CORE_PURPLE_COLORS, + ...createTextColors( CORE_PURPLE_COLORS ), + ...createRgbaColors( CORE_PURPLE_COLORS ), +}; + +export const BLUE_COLORS = { + ...CORE_BLUE_COLORS, + ...createTextColors( CORE_BLUE_COLORS ), + ...createRgbaColors( CORE_BLUE_COLORS ), +}; + +export const WORDPRESS_COLORS = { + ...DARK_GRAY_COLORS, + ...LIGHT_GRAY_COLORS, + ...RED_COLORS, + ...ORANGE_COLORS, + ...YELLOW_COLORS, + ...GREEN_COLORS, + ...PURPLE_COLORS, + ...BLUE_COLORS, +}; + +export const G2_COLORS = { + black: '#000000', + blueberry: '#3858E9', + blueberryDark: '#1D35B4', + greens: '#33F078', + grey: '#40464D', + greyBlack: '#1E1E1E', + lightBlue: '#33F078', + lightGrey: '#40464D', + lighterGrey: '#dddddd', + pomegrade: '#E26F56', + wordpressBlue: '#007cba', + white: '#ffffff', +}; + +export const BACKGROUND_COLOR_PROPS = { + colorBackgroundBlue: get( 'blueRgba10' ), + colorBackgroundBlueText: get( 'blue900' ), + + colorBackgroundDarkGray: get( 'darkGrayRgba10' ), + colorBackgroundDarkGrayText: get( 'darkGray900' ), + + colorBackgroundGreen: get( 'greenRgba10' ), + colorBackgroundGreenText: get( 'green900' ), + + colorBackgroundLightGray: get( 'lightGrayRgba10' ), + colorBackgroundLightGrayText: get( 'lightGray900' ), + + colorBackgroundOrange: get( 'orangeRgba10' ), + colorBackgroundOrangeText: get( 'orange900' ), + + colorBackgroundPurple: get( 'purpleRgba10' ), + colorBackgroundPurpleText: get( 'purple900' ), + + colorBackgroundRed: get( 'redRgba10' ), + colorBackgroundRedText: get( 'red900' ), + + colorBackgroundYellow: get( 'yellowRgba10' ), + colorBackgroundYellowText: get( 'yellow900' ), +}; + +export const DARK_MODE_COLORS = { + colorBackgroundBlue: get( 'blueRgba20' ), + colorBackgroundBlueText: get( 'blue300' ), + + colorBackgroundDarkGray: get( 'darkGrayRgba20' ), + colorBackgroundDarkGrayText: get( 'white' ), + + colorBackgroundGreen: get( 'greenRgba20' ), + colorBackgroundGreenText: get( 'green300' ), + + colorBackgroundLightGray: get( 'lightGrayRgba20' ), + colorBackgroundLightGrayText: get( 'white' ), + + colorBackgroundOrange: get( 'orangeRgba20' ), + colorBackgroundOrangeText: get( 'orange300' ), + + colorBackgroundPurple: get( 'purpleRgba20' ), + colorBackgroundPurpleText: get( 'purple300' ), + + colorBackgroundRed: get( 'redRgba20' ), + colorBackgroundRedText: get( 'red300' ), + + colorBackgroundYellow: get( 'yellowRgba20' ), + colorBackgroundYellowText: get( 'yellow300' ), +}; + +export const DARK_MODE_RGBA_COLORS = { + ...createRgbaColors( CORE_BLUE_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_GREEN_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_ORANGE_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_PURPLE_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_RED_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_YELLOW_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_DARK_GRAY_COLORS, /* isDark */ true ), + ...createRgbaColors( CORE_LIGHT_GRAY_COLORS, /* isDark */ true ), +}; diff --git a/packages/components/src/ui/styles/theme/tokens/index.js b/packages/components/src/ui/styles/theme/tokens/index.js new file mode 100644 index 0000000000000..1bae1c0e497ca --- /dev/null +++ b/packages/components/src/ui/styles/theme/tokens/index.js @@ -0,0 +1 @@ +export * from './colors'; diff --git a/packages/components/src/ui/styles/theme/utils.js b/packages/components/src/ui/styles/theme/utils.js new file mode 100644 index 0000000000000..700acd2e2e132 --- /dev/null +++ b/packages/components/src/ui/styles/theme/utils.js @@ -0,0 +1,122 @@ +/** + * External dependencies + */ +/** + * Internal dependencies + */ +import { get } from '../../create-styles'; +import colorize from 'tinycolor2'; + +/** + * @param {number} value + * @return {string} Space. + */ +export function space( value ) { + return `calc(${ get( 'gridBase' ) } * ${ value })`; +} + +/** + * @param {Record} colors + * @return {Record} Text colors. + */ +export function createTextColors( colors ) { + /** @type {Record} */ + const colorSet = {}; + const entries = Object.entries( colors ); + const light = entries[ 0 ][ 1 ]; + const lighter = colorize( light ).lighten( 15 ).toHexString(); + const dark = entries[ entries.length - 1 ][ 1 ]; + const darker = colorize( dark ).darken( 15 ).toHexString(); + + for ( const [ color, value ] of entries ) { + colorSet[ `${ color }Text` ] = colorize + .mostReadable( value, [ lighter, light, dark, darker ] ) + .toHexString(); + } + + return colorSet; +} + +/** + * + * @param {Record} colors + * @param {boolean} [isDark=false] + * @return {Record} Rgba colors. + */ +export function createRgbaColors( colors, isDark = false ) { + /** @type {Record} */ + const colorSet = {}; + const entries = Object.entries( colors ); + const [ baseColorName, baseColorValue ] = entries[ 2 ]; + const [ colorName ] = baseColorName.split( /\d+/ ); + + const ranges = [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ]; + + const mixBase = isDark ? '#000' : '#fff'; + const readabilityTextBase = isDark ? '#fff' : '#000'; + const adjustMethod = isDark ? 'darken' : 'lighten'; + + ranges.forEach( ( range, index ) => { + let enhancedColorValue = baseColorValue; + + enhancedColorValue = colorize( enhancedColorValue ) + .setAlpha( range / 100 ) + .toRgbString(); + + const testColor = colorize + .mix( baseColorValue, mixBase, index ) + .toRgbString(); + + const isReadable = colorize.isReadable( + testColor, + readabilityTextBase, + {} + ); + + if ( ! isReadable ) { + enhancedColorValue = colorize( enhancedColorValue ) + [ adjustMethod ]( 20 ) + .toRgbString(); + } + + colorSet[ `${ colorName }Rgba${ range }` ] = enhancedColorValue; + } ); + + return colorSet; +} + +/** + * @param {string} key + * @param {import('tinycolor2').ColorInput} color + * @return {Record} Rgb colors. + */ +export function generateRgbColors( key, color ) { + /** @type {Record} */ + const colorSet = { + [ key ]: color, + }; + + const ranges = [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ]; + + ranges.forEach( ( index ) => { + colorSet[ `${ key }Rgba${ index }` ] = colorize( color ) + .setAlpha( index / 100 ) + .toRgbString(); + } ); + + return colorSet; +} + +/** + * @param {import('tinycolor2').ColorInput} color + */ +export function generateColorAdminColors( color ) { + return generateRgbColors( 'colorAdmin', color ); +} + +/** + * @param {import('tinycolor2').ColorInput} color + */ +export function generateColorDestructiveColors( color ) { + return generateRgbColors( 'colorDestructive', color ); +} diff --git a/packages/components/src/ui/utils/colors.js b/packages/components/src/ui/utils/colors.js index fb9fc559f6d6e..05195351e8bcd 100644 --- a/packages/components/src/ui/utils/colors.js +++ b/packages/components/src/ui/utils/colors.js @@ -97,3 +97,42 @@ export function getOptimalTextShade( backgroundColor ) { return result === '#000000' ? 'dark' : 'light'; } + +/** + * Retrieves the computed text color. This is useful for getting the + * value of a CSS variable color. + * + * @param {string | unknown} color + * + * @return {string} The computed text color. + */ +function __getComputedColor( color ) { + if ( typeof color !== 'string' ) return ''; + + if ( isColor( color ) ) return color; + + if ( ! color.includes( 'var(' ) ) return ''; + if ( typeof document === 'undefined' ) return ''; + + // Attempts to gracefully handle CSS variables color values. + const el = getColorComputationNode(); + if ( ! el ) return ''; + + el.style.color = color; + // Grab the style + const computedColor = window?.getComputedStyle( el ).color; + // Reset + el.style.color = ''; + + return computedColor || ''; +} + +/** + * Retrieves the computed text color. This is useful for getting the + * value of a CSS variable color. + * + * @param {string | unknown} color + * + * @return {string} The computed text color. + */ +export const getComputedColor = memoize( __getComputedColor ); From 4b2b5e236fdf1a2b07986e0d8813f6c34aa211ed Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Thu, 8 Apr 2021 10:40:57 -0700 Subject: [PATCH 02/19] Remove IE11 shim for CSS variables --- .../create-compiler/create-compiler.js | 6 +- .../create-compiler/plugins/css-variables.js | 77 ------------ .../create-compiler/plugins/index.js | 13 +- .../create-style-system.js | 11 +- .../create-root-store.js | 111 ------------------ .../css-custom-properties/get-prop-value.js | 71 ----------- .../css-custom-properties/index.js | 2 - .../transform-content.js | 98 ---------------- .../css-custom-properties/utils.js | 54 --------- 9 files changed, 3 insertions(+), 440 deletions(-) delete mode 100644 packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js delete mode 100644 packages/components/src/ui/create-styles/css-custom-properties/create-root-store.js delete mode 100644 packages/components/src/ui/create-styles/css-custom-properties/get-prop-value.js delete mode 100644 packages/components/src/ui/create-styles/css-custom-properties/index.js delete mode 100644 packages/components/src/ui/create-styles/css-custom-properties/transform-content.js delete mode 100644 packages/components/src/ui/create-styles/css-custom-properties/utils.js diff --git a/packages/components/src/ui/create-styles/create-compiler/create-compiler.js b/packages/components/src/ui/create-styles/create-compiler/create-compiler.js index 9885f59678b28..e138ffb2cd4d8 100644 --- a/packages/components/src/ui/create-styles/create-compiler/create-compiler.js +++ b/packages/components/src/ui/create-styles/create-compiler/create-compiler.js @@ -7,7 +7,6 @@ import mitt from 'mitt'; /** * Internal dependencies */ -import { RootStore } from '../css-custom-properties'; import { createCSS } from './create-css'; import { createPlugins } from './plugins'; import { breakpoints, generateInterpolationName } from './utils'; @@ -15,7 +14,6 @@ import { breakpoints, generateInterpolationName } from './utils'; const defaultOptions = { key: 'css', specificityLevel: 1, - rootStore: new RootStore(), }; /* eslint-disable jsdoc/valid-types */ @@ -32,7 +30,6 @@ const defaultOptions = { * @typedef {import('create-emotion').Options & { * key?: string, * specificityLevel?: number, - * rootStore: import('../css-custom-properties').RootStore * }} CreateCompilerOptions */ @@ -46,12 +43,11 @@ export function createCompiler( options ) { ...options, }; - const { key, rootStore, specificityLevel } = mergedOptions; + const { key, specificityLevel } = mergedOptions; const defaultPlugins = createPlugins( { key, specificityLevel, - rootStore, } ); if ( options.stylisPlugins ) { diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js b/packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js deleted file mode 100644 index 23771469048e7..0000000000000 --- a/packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Internal dependencies - */ -import { createRootStore } from '../../css-custom-properties'; -import { transformContent } from '../../css-custom-properties/transform-content'; -import { hasVariable } from '../../css-custom-properties/utils'; -import { STYLIS_CONTEXTS, STYLIS_TOKENS } from './utils'; - -// Detects native CSS varialble support -// https://github.com/jhildenbiddle/css-vars-ponyfill/blob/master/src/index.js -const isNativeSupport = - typeof window !== 'undefined' && window?.CSS?.supports?.( '(--a: 0)' ); - -/* - * This plugin is for the stylis library. It's the CSS compiler used by - * CSS-in-JS libraries like Emotion. - * - * https://github.com/thysultan/stylis.js - */ - -const defaultOptions = { - rootStore: createRootStore(), - skipSupportedBrowsers: true, -}; - -/* - * Generates fallback values for CSS rule declarations that contain CSS var(). - * This plugin parses uses specified fallback values within the var() - * function. If one is not provided, it will attempt to use the matching - * variable declared at the :root scope. - */ -function stylisPluginCssVariables( - /* istanbul ignore next */ - options = {} -) { - const { rootStore, skipSupportedBrowsers } = { - ...defaultOptions, - ...options, - }; - - const plugin = ( - /** @type {number} */ context, - /** @type {string} */ content, - /** @type {unknown} */ _, - /** @type {unknown} */ __, - /** @type {unknown} */ ___, - /** @type {unknown} */ ____, - /** @type {unknown} */ _____, - /** @type {number} */ type - ) => { - // Skip generating CSS variable fallbacks for supported browsers - if ( skipSupportedBrowsers && isNativeSupport ) return; - - // Borrowed guard implementation from: - // https://github.com/Andarist/stylis-plugin-extra-scope/blob/master/src/index.js#L15 - /* istanbul ignore next */ - if ( - context !== STYLIS_CONTEXTS.SELECTOR_BLOCK || - type === STYLIS_TOKENS.KEYFRAME - ) { - return; - } - - // We only need to process the content if a CSS var() is used. - if ( ! hasVariable( content ) ) return; - - // We'll parse the content to match variables to their custom properties (if possible). - const nextContent = transformContent( content, rootStore ); - - // Lastly, we'll provide stylis with our enhanced CSS variable supported content. - return nextContent; - }; - - return plugin; -} - -export default stylisPluginCssVariables; diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/index.js b/packages/components/src/ui/create-styles/create-compiler/plugins/index.js index b83b8b25c7b88..1c0a5ece5d565 100644 --- a/packages/components/src/ui/create-styles/create-compiler/plugins/index.js +++ b/packages/components/src/ui/create-styles/create-compiler/plugins/index.js @@ -6,11 +6,8 @@ import cssGridPlugin from 'styled-griddie'; /** * Internal dependencies */ -import cssVariablesPlugin from './css-variables'; import specificityPlugin from './extra-specificity'; -const isProd = process.env.NODE_ENV === 'production'; - /** * A collection of custom Stylis plugins to enhance the way the compiler (Emotion) * generates selectors and CSS rules. @@ -18,18 +15,10 @@ const isProd = process.env.NODE_ENV === 'production'; * @param {Object} options * @param {number} [options.specificityLevel=7] * @param {string} [options.key='css'] - * @param {boolean} [options.skipSupportedBrowsers] - * @param {import('../../css-custom-properties').RootStore} [options.rootStore] * @return {import('@emotion/stylis').Plugin[]} The list of stylis plugins. */ -export function createPlugins( { - specificityLevel = 1, - key = 'css', - rootStore, - skipSupportedBrowsers = isProd, -} ) { +export function createPlugins( { specificityLevel = 1, key = 'css' } ) { return [ - cssVariablesPlugin( { skipSupportedBrowsers, rootStore } ), specificityPlugin( { level: specificityLevel, key } ), // @ts-ignore styled-griddie imports StylisPlugin from `styled-components` which has different types from the actual one we're using here cssGridPlugin, diff --git a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js index 90c21d2c2cddc..d99373f958d08 100644 --- a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js +++ b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js @@ -2,7 +2,6 @@ * Internal dependencies */ import { createCompiler } from '../create-compiler'; -import { createRootStore } from '../css-custom-properties'; import { createCoreElement } from './create-core-element'; import { createCoreElements } from './create-core-elements'; import { createStyledComponents } from './create-styled-components'; @@ -28,7 +27,6 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; * @property {(value: keyof (TConfig & TDarkConfig & THCConfig & TDarkHCConfig) | TGeneratedTokens) => string} get The primary function to retrieve Style system variables. * @property {import('./polymorphic-component').CreateStyled} styled A set of styled components. * @property {import('react').ComponentType} View The base component. - * @property {import('../css-custom-properties').RootStore} rootStore The root store. */ /** @@ -84,16 +82,10 @@ export function createStyleSystem( options = defaultOptions ) { highContrastModeConfig, } ); - const rootStore = createRootStore( globalStyles.globalVariables ); - rootStore.setState( globalStyles.globalVariables ); - /** * Compiler (Custom Emotion instance). */ - const compiler = createCompiler( { - ...compilerOptions, - rootStore, - } ); + const compiler = createCompiler( compilerOptions ); const { css, cx } = compiler; /** @@ -142,7 +134,6 @@ export function createStyleSystem( options = defaultOptions ) { ) => `var(${ createToken( key.toString() ) })`, styled, View, - rootStore, }; return styleSystem; diff --git a/packages/components/src/ui/create-styles/css-custom-properties/create-root-store.js b/packages/components/src/ui/create-styles/css-custom-properties/create-root-store.js deleted file mode 100644 index cc3732031bc3d..0000000000000 --- a/packages/components/src/ui/create-styles/css-custom-properties/create-root-store.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Internal dependencies - */ -import { getPropValue } from './get-prop-value'; -import { hasVariable } from './utils'; - -/** - * Stores CSS config variables that are expected to be added to :root. - * This is used for CSS variable fallback handling for IE 11. - */ -export class RootStore { - /** - * - * @param {Record} initialState - */ - constructor( initialState = {} ) { - /** - * @type {Record} - */ - this.state = {}; - this.setState( initialState ); - } - - /** - * Retrieve a value from the state. - * - * @param {string} key The key to retrieve. - * @return {string} The value. - */ - get( key ) { - return this.state[ key ]; - } - - /** - * Retrieves the current state. - * - * @return {Record} The state. - */ - getState() { - return this.state; - } - - /** - * Sets the state. - * - * @param {Record} next The next state to merge into the current state. - * @return {Record} The state. - */ - setState( next = {} ) { - this._updateState( next ); - this._resolveVariablesInStateValue(); - - return this.state; - } - - /** - * Updates the state. - * - * @param {Record} next The next state to merge into the current state. - */ - _updateState( next = {} ) { - this.state = Object.freeze( { ...this.state, ...next } ); - } - - /** - * Resolves potential CSS variables that may exist within the state's values. - */ - _resolveVariablesInStateValue() { - /** @type {Record} */ - const next = {}; - /** - * Filter out entries so that we only target values with CSS variables. - */ - const entries = Object.entries( this.state ).filter( ( [ , v ] ) => - hasVariable( v ) - ); - - for ( const [ k, v ] of entries ) { - const [ , value ] = getPropValue( `resolve: ${ v }`, this ); - /** - * Set the value for the next state, if available. - */ - if ( value ) { - next[ k ] = value; - } - } - - this._updateState( next ); - - /** - * Run this function again if there are any unresolved values. - */ - if ( entries.length ) { - this._resolveVariablesInStateValue(); - } - } -} - -/** - * Creates a RootStore instance. - * This store contains a collection of CSS variables that is expected to - * be added to the :root {} node. - * - * @param {Record} initialState The initial config. - * @return {RootStore} The RootStore instance. - */ -export function createRootStore( initialState = {} ) { - const store = new RootStore( initialState ); - - return store; -} diff --git a/packages/components/src/ui/create-styles/css-custom-properties/get-prop-value.js b/packages/components/src/ui/create-styles/css-custom-properties/get-prop-value.js deleted file mode 100644 index 0dac5f3d87e96..0000000000000 --- a/packages/components/src/ui/create-styles/css-custom-properties/get-prop-value.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Internal dependencies - */ -import { sanitizeParens, VAR_REG_EXP } from './utils'; - -/** - * Interprets and retrieves the CSS property and value of a declaration rule. - * - * @param {string} declaration A CSS declaration rule to parse. - * @param {import('./create-root-store').RootStore} rootStore A store for CSS root variables. - * @return {[string, string | undefined]} [prop, value] parsed from the declaration. - */ -export function getPropValue( declaration, rootStore ) { - let hasFallbackValue = false; - // Start be separating (and preparing) the prop and value from the declaration. - /** @type {string} */ - let prop; - /** @type {string | undefined} */ - let value; - [ prop, value ] = declaration.split( /:/ ); - prop = prop.trim(); - - // Searching for uses of var(). - const matches = - value.match( VAR_REG_EXP ) || - /* istanbul ignore next */ - []; - - for ( let match of matches ) { - match = match.trim(); - // Splitting again allows us to traverse through nested vars(). - const entries = match - .replace( / /g, '' ) - .split( 'var(' ) - .filter( Boolean ); - - for ( const entry of entries ) { - // Removes extra parentheses - const parsedValue = sanitizeParens( entry ); - /** - * Splits a CSS variable into it's custom property name and fallback. - * - * Before: - * '--bg, black' - * - * After: - * ['--bg', 'black'] - */ - const [ customProp, ...fallbacks ] = parsedValue.split( ',' ); - const customFallback = fallbacks.join( ',' ); - - // Attempt to get the CSS variable from rootStore. Otherwise, use the provided fallback. - const fallback = - ( rootStore && rootStore.get( customProp ) ) || customFallback; - - if ( fallback ) { - hasFallbackValue = true; - /* - * If a valid fallback value is discovered, we'll replace it in - * our value. - */ - value = value.replace( match, fallback ); - } - } - } - - // We only want to return a value if we're able to locate a fallback value. - value = hasFallbackValue ? sanitizeParens( value ) : undefined; - - return [ prop, value ]; -} diff --git a/packages/components/src/ui/create-styles/css-custom-properties/index.js b/packages/components/src/ui/create-styles/css-custom-properties/index.js deleted file mode 100644 index f201ad165ca26..0000000000000 --- a/packages/components/src/ui/create-styles/css-custom-properties/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './create-root-store'; -export * from './get-prop-value'; diff --git a/packages/components/src/ui/create-styles/css-custom-properties/transform-content.js b/packages/components/src/ui/create-styles/css-custom-properties/transform-content.js deleted file mode 100644 index 384456446b02d..0000000000000 --- a/packages/components/src/ui/create-styles/css-custom-properties/transform-content.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * External dependencies - */ -import memoize from 'memize'; - -/** - * Internal dependencies - */ -import { getPropValue } from './get-prop-value'; -import { hasVariable, isCustomProperty } from './utils'; - -/** - * Interprets and retrieves the CSS fallback value of a declaration rule. - * - * @param {string} declaration A CSS declaration rule to parse. - * @param {import('./create-root-store').RootStore} rootStore A store for CSS root variables. - * @return {string | undefined} A CSS declaration rule with a fallback (if applicable). - */ -export function getFallbackDeclaration( declaration, rootStore ) { - if ( ! hasVariable( declaration ) && ! isCustomProperty( declaration ) ) - return undefined; - - const [ prop, value ] = getPropValue( declaration, rootStore ); - - return value ? [ prop, value ].join( ':' ) : undefined; -} - -/** - * Parses the incoming content from stylis to add fallback CSS values for - * variables. - * - * @param {string} content Stylis content to parse. - * @param {import('./create-root-store').RootStore} rootStore A store for CSS root variables. - * @return {string | undefined} The transformed content with CSS variable fallbacks. - */ -export function baseTransformContent( content, rootStore ) { - /* - * Attempts to deconstruct the content to retrieve prop/value - * CSS declaration pairs. - * - * Before: - * 'background-color:var(--bg, black); font-size:14px;' - * - * After: - * ['background-color:var(--bg, black)', ' font-size:14px'] - */ - const declarations = content.split( ';' ).filter( Boolean ); - let didTransform = false; - - /* - * With the declaration collection, we'll iterate over every declaration - * to provide fallbacks (if applicable.) - */ - const parsed = declarations.reduce( ( - /** @type {string[]} */ styles, - /** @type {string} */ declaration - ) => { - // If no CSS variable is used, we return the declaration untouched. - if ( ! hasVariable( declaration ) ) { - return [ ...styles, declaration ]; - } - // Retrieve the fallback a CSS variable is used in this declaration. - const fallback = getFallbackDeclaration( declaration, rootStore ); - /* - * Prepend the fallback in our styles set. - * - * Before: - * [ - * ...styles, - * 'background-color:var(--bg, black);' - * ] - * - * After: - * [ - * ...styles, - * 'background:black;', - * 'background-color:var(--bg, black);' - * ] - */ - if ( fallback ) { - didTransform = true; - - return [ ...styles, fallback, declaration ]; - } - return [ ...styles, declaration ]; - }, [] ); - - /* - * We'll rejoin our declarations with a ; separator. - * Note: We need to add a ; at the end for stylis to interpret correctly. - */ - const result = parsed.join( ';' ).concat( ';' ); - - // We only want to return a value if we're able to locate a fallback value. - return didTransform ? result : undefined; -} - -export const transformContent = memoize( baseTransformContent ); diff --git a/packages/components/src/ui/create-styles/css-custom-properties/utils.js b/packages/components/src/ui/create-styles/css-custom-properties/utils.js deleted file mode 100644 index f5a30e7921b0a..0000000000000 --- a/packages/components/src/ui/create-styles/css-custom-properties/utils.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * External dependencies - */ -import { repeat } from 'lodash'; - -export const VAR_REG_EXP = new RegExp( /var\(.*?\)[ ) ]*/, 'g' ); - -/** - * Checks to see if a CSS declaration rule is a CSS variable (e.g. --font: 14px) - * - * @param {string} declaration A CSS declaration rule. - * @return {boolean} Result of whether declaration is a CSS variable. - */ -export function isCustomProperty( declaration ) { - return declaration.indexOf( '--' ) === 0; -} - -/** - * Checks to see if a CSS declaration rule uses var(). - * - * @param {string} declaration A CSS declaration rule. - * @return {boolean} Result of whether declaration contains a CSS variable. - */ -export function hasVariable( declaration ) { - return declaration?.includes?.( 'var(' ); -} - -/** - * Appends or trims parens from a value. - * - * @param {string} value Value to sanitize. - * @return {string} The sanitized value - */ -export function sanitizeParens( value ) { - const parenStartCount = value.match( /\(/g )?.length || 0; - const parenEndCount = value.match( /\)/g )?.length || 0; - - const parenAppendCound = parenStartCount - parenEndCount; - const parenTrimCount = parenEndCount - parenStartCount; - - let result; - - if ( parenStartCount > parenEndCount ) { - // We need to append ) to the end if there are any missing. - const append = repeat( ')', parenAppendCound ); - result = `${ value }${ append }`; - } else { - // Otherwise, we need to trim the extra parens at the end. - const trimRegExp = new RegExp( `((\\)){${ parenTrimCount }})$`, 'gi' ); - result = value.replace( trimRegExp, '' ); - } - - return result?.trim(); -} From f75330f7422f441386488e1f1bb6ba0ce5f2068c Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Thu, 8 Apr 2021 10:53:27 -0700 Subject: [PATCH 03/19] Add missing warning type reference --- packages/components/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 96bed3dde24e4..09f939a68d126 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -15,7 +15,8 @@ { "path": "../icons" }, { "path": "../is-shallow-equal" }, { "path": "../primitives" }, - { "path": "../react-i18n" } + { "path": "../react-i18n" }, + { "path": "../warning" } ], "include": [ "src/animate/**/*", From eb147d2f138ad1740be3a091eb29e4599ea1467d Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Thu, 8 Apr 2021 11:07:18 -0700 Subject: [PATCH 04/19] Add default value to createCompiler --- .../src/ui/create-styles/create-compiler/create-compiler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/ui/create-styles/create-compiler/create-compiler.js b/packages/components/src/ui/create-styles/create-compiler/create-compiler.js index e138ffb2cd4d8..4b45c3bbdbebc 100644 --- a/packages/components/src/ui/create-styles/create-compiler/create-compiler.js +++ b/packages/components/src/ui/create-styles/create-compiler/create-compiler.js @@ -37,7 +37,7 @@ const defaultOptions = { * @param {CreateCompilerOptions} options * @return {Compiler} The compiler. */ -export function createCompiler( options ) { +export function createCompiler( options = {} ) { const mergedOptions = { ...defaultOptions, ...options, From 119f48a5675350766ed2f7135cc7aa1b618db815 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Fri, 9 Apr 2021 07:51:05 -0700 Subject: [PATCH 05/19] Specify exports --- packages/components/src/ui/styles/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/src/ui/styles/index.js b/packages/components/src/ui/styles/index.js index 7c4781d318933..c08bc284a4ca8 100644 --- a/packages/components/src/ui/styles/index.js +++ b/packages/components/src/ui/styles/index.js @@ -1,10 +1,10 @@ -export * from './core'; +export { get } from './core'; export { cache, css, cx, injectGlobal, keyframes } from './style-system'; - -export * from './styled'; -export * from './hooks'; -export * from './mixins'; -export * from './namespaces'; +export { styled } from './styled'; +export { useResponsiveValue, useRTL } from './hooks'; +export { space } from './mixins'; +export { ns } from './namespaces'; export { config, createTheme, SUPPORTED_COLORS } from './theme'; -export * from './components'; +/** @typedef {import('./components').StyleFrameProviderProps} StyleFrameProviderProps */ +export { StyleFrameProvider } from './components'; From 481c951db5b2d6524eb7bef40ab27359a3fb1ce1 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Fri, 9 Apr 2021 07:52:58 -0700 Subject: [PATCH 06/19] Restore `ui` export and remove unused features --- packages/components/src/ui/styles/index.js | 4 +--- .../components/src/ui/styles/namespaces.js | 19 ------------------- packages/components/src/ui/styles/ui.js | 10 ++++++++++ 3 files changed, 11 insertions(+), 22 deletions(-) delete mode 100644 packages/components/src/ui/styles/namespaces.js create mode 100644 packages/components/src/ui/styles/ui.js diff --git a/packages/components/src/ui/styles/index.js b/packages/components/src/ui/styles/index.js index c08bc284a4ca8..17bb8950896c3 100644 --- a/packages/components/src/ui/styles/index.js +++ b/packages/components/src/ui/styles/index.js @@ -1,9 +1,7 @@ -export { get } from './core'; export { cache, css, cx, injectGlobal, keyframes } from './style-system'; export { styled } from './styled'; export { useResponsiveValue, useRTL } from './hooks'; -export { space } from './mixins'; -export { ns } from './namespaces'; +export { ui } from './ui'; export { config, createTheme, SUPPORTED_COLORS } from './theme'; /** @typedef {import('./components').StyleFrameProviderProps} StyleFrameProviderProps */ diff --git a/packages/components/src/ui/styles/namespaces.js b/packages/components/src/ui/styles/namespaces.js deleted file mode 100644 index cfe01d2c6db4a..0000000000000 --- a/packages/components/src/ui/styles/namespaces.js +++ /dev/null @@ -1,19 +0,0 @@ -export const COMPONENT_NAMESPACE = 'data-g2-component'; - -/* eslint-disable jsdoc/valid-types */ -/** - * Creates a dedicated context namespace HTML attribute for components. - * ns is short for "namespace" - * - * @example - * ```jsx - *
- * ``` - * - * @param {string} componentName The name for the component. - * @return {{ [COMPONENT_NAMESPACE]: string }} A props object with the namespaced HTML attribute. - */ -export function ns( componentName ) { - /* eslint-enable jsdoc/valid-types */ - return { [ COMPONENT_NAMESPACE ]: componentName }; -} diff --git a/packages/components/src/ui/styles/ui.js b/packages/components/src/ui/styles/ui.js new file mode 100644 index 0000000000000..b7b244db3e08b --- /dev/null +++ b/packages/components/src/ui/styles/ui.js @@ -0,0 +1,10 @@ +/** + * Internal dependencies + */ +import { get } from './core'; +import { space } from './mixins'; + +export const ui = { + get, + space, +}; From f26ba289af15385f4dd8faf4b90c5e599dcdca54 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Fri, 9 Apr 2021 07:54:36 -0700 Subject: [PATCH 07/19] Remove further unused features and clean up exports --- packages/components/src/ui/styles/index.js | 4 ++-- packages/components/src/ui/styles/style-system.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/components/src/ui/styles/index.js b/packages/components/src/ui/styles/index.js index 17bb8950896c3..9224f012a98d8 100644 --- a/packages/components/src/ui/styles/index.js +++ b/packages/components/src/ui/styles/index.js @@ -1,8 +1,8 @@ -export { cache, css, cx, injectGlobal, keyframes } from './style-system'; +export { css } from './css'; +export { cache, cx, injectGlobal, keyframes } from './style-system'; export { styled } from './styled'; export { useResponsiveValue, useRTL } from './hooks'; export { ui } from './ui'; -export { config, createTheme, SUPPORTED_COLORS } from './theme'; /** @typedef {import('./components').StyleFrameProviderProps} StyleFrameProviderProps */ export { StyleFrameProvider } from './components'; diff --git a/packages/components/src/ui/styles/style-system.js b/packages/components/src/ui/styles/style-system.js index f3393db40cd58..90bd1c7971663 100644 --- a/packages/components/src/ui/styles/style-system.js +++ b/packages/components/src/ui/styles/style-system.js @@ -2,7 +2,6 @@ * Internal dependencies */ import { compiler } from './system'; -export { css } from './css'; export const { breakpoints, From 884e31baec5808c7207acc5e0cd705d1568789ec Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Fri, 9 Apr 2021 07:58:03 -0700 Subject: [PATCH 08/19] Fix font families --- packages/components/src/ui/styles/theme/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/ui/styles/theme/config.js b/packages/components/src/ui/styles/theme/config.js index 4aa3ba69ec0a5..5207307b35416 100644 --- a/packages/components/src/ui/styles/theme/config.js +++ b/packages/components/src/ui/styles/theme/config.js @@ -51,8 +51,8 @@ const COLOR_PROPS = { const FONT_PROPS = { fontFamily: - 'Inter,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",sans-serif', - fontFamilyMono: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace', + '-apple-system, BlinkMacSystemFont,"Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell,"Helvetica Neue", sans-serif', + fontFamilyMono: 'Menlo, Consolas, monaco, monospace', fontSize: '13px', fontSizeH1: `calc(2.44 * ${ get( 'fontSize' ) })`, fontSizeH2: `calc(1.95 * ${ get( 'fontSize' ) })`, From b53c5e51fdb0db517f71eb80740cf698db344b5b Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Mon, 12 Apr 2021 06:54:01 -0700 Subject: [PATCH 09/19] Fix import in test --- packages/components/src/ui/styles/test/scales.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/ui/styles/test/scales.js b/packages/components/src/ui/styles/test/scales.js index 1446f45ceb544..05954f9babee2 100644 --- a/packages/components/src/ui/styles/test/scales.js +++ b/packages/components/src/ui/styles/test/scales.js @@ -1,11 +1,11 @@ /** * Internal dependencies */ -import { space } from '..'; +import { ui } from '..'; import { getScaleStyles } from '../css'; describe( 'scales', () => { - test( 'should transform space values', () => { + test( 'should transform ui.space values', () => { const numberValues = { gridGap: 4, gridColumnGap: 4, @@ -21,7 +21,7 @@ describe( 'scales', () => { const result = {}; assert[ key ] = value; - result[ key ] = space( value ); + result[ key ] = ui.space( value ); expect( getScaleStyles( assert ) ).toEqual( result ); } @@ -41,7 +41,7 @@ describe( 'scales', () => { const result = {}; assert[ key ] = value; - result[ key ] = space( value ); + result[ key ] = ui.space( value ); expect( getScaleStyles( assert ) ).toEqual( result ); } From d1c7e146d93650d0e37537ac22ff9b5af1c2a506 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Mon, 12 Apr 2021 14:01:18 -0700 Subject: [PATCH 10/19] Pare down the themes to just the basics --- .../create-style-system.js | 35 +- packages/components/src/ui/styles/system.js | 147 +------- .../components/src/ui/styles/theme/config.js | 349 ++---------------- .../theme/dark-high-contrast-mode-config.js | 8 +- .../src/ui/styles/theme/dark-mode-config.js | 33 +- .../components/src/ui/styles/theme/theme.js | 27 -- .../src/ui/styles/theme/tokens/colors.js | 206 ----------- .../src/ui/styles/theme/tokens/index.js | 1 - 8 files changed, 50 insertions(+), 756 deletions(-) delete mode 100644 packages/components/src/ui/styles/theme/tokens/colors.js delete mode 100644 packages/components/src/ui/styles/theme/tokens/index.js diff --git a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js index d99373f958d08..5c437ed29adc7 100644 --- a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js +++ b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js @@ -12,11 +12,10 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; /* eslint-disable jsdoc/valid-types */ /** - * @template {Record} TConfig - * @template {Record} TDarkConfig - * @template {Record} THCConfig - * @template {Record} TDarkHCConfig - * @template {string} TGeneratedTokens + * @template {Record | {}} TConfig + * @template {Record | {}} TDarkConfig + * @template {Record | {}} THCConfig + * @template {Record | {}} TDarkHCConfig * @typedef CreateStyleSystemObjects * @property {import('./polymorphic-component').CoreElements} core A set of coreElements. * @property {import('../create-compiler').Compiler} compiler The Style system compiler (a custom Emotion instance). @@ -24,17 +23,16 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; * @property {import('../create-compiler').Compiler['css']} css A function to compile CSS styles. * @property {import('../create-compiler').Compiler['cx']} cx A function to resolve + combine classNames. * @property {(tokenName: string) => string} createToken A function to generate a design token (CSS variable) used by the system. - * @property {(value: keyof (TConfig & TDarkConfig & THCConfig & TDarkHCConfig) | TGeneratedTokens) => string} get The primary function to retrieve Style system variables. + * @property {(value: keyof (TConfig & TDarkConfig & THCConfig & TDarkHCConfig)) => string} get The primary function to retrieve Style system variables. * @property {import('./polymorphic-component').CreateStyled} styled A set of styled components. * @property {import('react').ComponentType} View The base component. */ /** - * @template {Record} TConfig - * @template {Record} TDarkConfig - * @template {Record} THCConfig - * @template {Record} TDarkHCConfig - * @template {string} TGeneratedTokens + * @template {Record | {}} TConfig + * @template {Record | {}} TDarkConfig + * @template {Record | {}} THCConfig + * @template {Record | {}} TDarkHCConfig * @typedef CreateStyleSystemOptions * @property {import('create-emotion').ObjectInterpolation} baseStyles The base styles. * @property {TConfig} config The base theme config. @@ -54,13 +52,12 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; * const blueStyleSystem = createStyleSystem({ baseStyles }); * ``` * - * @template {Record} TConfig - * @template {Record} TDarkConfig - * @template {Record} THCConfig - * @template {Record} TDarkHCConfig - * @template {string} TGeneratedTokens - * @param {CreateStyleSystemOptions} options Options to create a Style system with. - * @return {CreateStyleSystemObjects} A collection of functions and elements from the generated Style system. + * @template {Record | {}} TConfig + * @template {Record | {}} TDarkConfig + * @template {Record | {}} THCConfig + * @template {Record | {}} TDarkHCConfig + * @param {CreateStyleSystemOptions} options Options to create a Style system with. + * @return {CreateStyleSystemObjects} A collection of functions and elements from the generated Style system. */ export function createStyleSystem( options = defaultOptions ) { const { @@ -129,7 +126,7 @@ export function createStyleSystem( options = defaultOptions ) { cx, get: ( /* eslint-disable jsdoc/no-undefined-types */ - /** @type {keyof TConfig | keyof TDarkConfig | keyof THCConfig | keyof TDarkHCConfig | TGeneratedTokens} */ key + /** @type {keyof TConfig | keyof TDarkConfig | keyof THCConfig | keyof TDarkHCConfig} */ key /* eslint-enable jsdoc/no-undefined-types */ ) => `var(${ createToken( key.toString() ) })`, styled, diff --git a/packages/components/src/ui/styles/system.js b/packages/components/src/ui/styles/system.js index ffaf5b11c37d9..01839d3ba2f3f 100644 --- a/packages/components/src/ui/styles/system.js +++ b/packages/components/src/ui/styles/system.js @@ -9,152 +9,7 @@ import { highContrastModeConfig, } from './theme'; -/* eslint-disable jsdoc/valid-types */ -/** - * @typedef { - | 'colorAdmin' - | 'colorAdminRgba10' - | 'colorAdminRgba20' - | 'colorAdminRgba30' - | 'colorAdminRgba40' - | 'colorAdminRgba50' - | 'colorAdminRgba60' - | 'colorAdminRgba70' - | 'colorAdminRgba80' - | 'colorAdminRgba90' - | 'colorDestructive' - | 'colorDestructiveRgba10' - | 'colorDestructiveRgba20' - | 'colorDestructiveRgba30' - | 'colorDestructiveRgba40' - | 'colorDestructiveRgba50' - | 'colorDestructiveRgba60' - | 'colorDestructiveRgba70' - | 'colorDestructiveRgba80' - | 'colorDestructiveRgba90' - | 'gray100Text' - | 'gray300Text' - | 'gray500Text' - | 'gray700Text' - | 'gray900Text' - | 'darkGray100Text' - | 'darkGray300Text' - | 'darkGray500Text' - | 'darkGray700Text' - | 'darkGray900Text' - | 'red100Text' - | 'red300Text' - | 'red500Text' - | 'red700Text' - | 'red900Text' - | 'orange100Text' - | 'orange300Text' - | 'orange500Text' - | 'orange700Text' - | 'orange900Text' - | 'yellow100Text' - | 'yellow300Text' - | 'yellow500Text' - | 'yellow700Text' - | 'yellow900Text' - | 'green100Text' - | 'green300Text' - | 'green500Text' - | 'green700Text' - | 'green900Text' - | 'purple100Text' - | 'purple300Text' - | 'purple500Text' - | 'purple700Text' - | 'purple900Text' - | 'purple100Text' - | 'purple300Text' - | 'purple500Text' - | 'purple700Text' - | 'purple900Text' - | 'grayRgba10' - | 'grayRgba20' - | 'grayRgba30' - | 'grayRgba40' - | 'grayRgba50' - | 'grayRgba60' - | 'grayRgba70' - | 'grayRgba80' - | 'grayRgba90' - | 'darkGrayRgba10' - | 'darkGrayRgba20' - | 'darkGrayRgba30' - | 'darkGrayRgba40' - | 'darkGrayRgba50' - | 'darkGrayRgba60' - | 'darkGrayRgba70' - | 'darkGrayRgba80' - | 'darkGrayRgba90' - | 'redRgba10' - | 'redRgba20' - | 'redRgba30' - | 'redRgba40' - | 'redRgba50' - | 'redRgba60' - | 'redRgba70' - | 'redRgba80' - | 'redRgba90' - | 'orangeRgba10' - | 'orangeRgba20' - | 'orangeRgba30' - | 'orangeRgba40' - | 'orangeRgba50' - | 'orangeRgba60' - | 'orangeRgba70' - | 'orangeRgba80' - | 'orangeRgba90' - | 'yellowRgba10' - | 'yellowRgba20' - | 'yellowRgba30' - | 'yellowRgba40' - | 'yellowRgba50' - | 'yellowRgba60' - | 'yellowRgba70' - | 'yellowRgba80' - | 'yellowRgba90' - | 'greenRgba10' - | 'greenRgba20' - | 'greenRgba30' - | 'greenRgba40' - | 'greenRgba50' - | 'greenRgba60' - | 'greenRgba70' - | 'greenRgba80' - | 'greenRgba90' - | 'purpleRgba10' - | 'purpleRgba20' - | 'purpleRgba30' - | 'purpleRgba40' - | 'purpleRgba50' - | 'purpleRgba60' - | 'purpleRgba70' - | 'purpleRgba80' - | 'purpleRgba90' - | 'blueRgba10' - | 'blueRgba20' - | 'blueRgba30' - | 'blueRgba40' - | 'blueRgba50' - | 'blueRgba60' - | 'blueRgba70' - | 'blueRgba80' - | 'blueRgba90' - - // Theme tokens that pop up throughout the codebase - | 'flexGap' - | 'flexItemDisplay' - | 'surfaceBackgroundSize' - | 'surfaceBackgroundSizeDotted' -} GeneratedDesignTokens - */ -/* eslint-enable jsdoc/valid-types */ - -/** @type {import('../create-styles').CreateStyleSystemOptions} */ +/** @type {import('../create-styles').CreateStyleSystemOptions} */ const systemConfig = { baseStyles: { MozOsxFontSmoothing: 'grayscale', diff --git a/packages/components/src/ui/styles/theme/config.js b/packages/components/src/ui/styles/theme/config.js index 5207307b35416..d8f94f0ed0f01 100644 --- a/packages/components/src/ui/styles/theme/config.js +++ b/packages/components/src/ui/styles/theme/config.js @@ -2,24 +2,7 @@ * Internal dependencies */ import { get } from '../../create-styles'; -import { flow } from '../presets/flow'; -import { BACKGROUND_COLOR_PROPS, G2_COLORS, WORDPRESS_COLORS } from './tokens'; -import { - generateColorAdminColors, - generateColorDestructiveColors, - space, -} from './utils'; - -export const SUPPORTED_COLORS = [ - 'blue', - 'red', - 'purple', - 'green', - 'yellow', - 'orange', - 'darkGray', - 'lightGray', -]; +import { rgba } from '../../../utils/colors'; const ANIMATION_PROPS = { transitionDuration: '200ms', @@ -30,23 +13,43 @@ const ANIMATION_PROPS = { transitionTimingFunctionControl: 'cubic-bezier(0.12, 0.8, 0.32, 1)', }; +const GRAY_COLORS = { + black: '#000', + gray900: '#1e1e1e', + gray700: '#757575', + gray600: '#949494', + gray500: '#bbb', + gray400: '#ccc', + gray300: '#ddd', + gray200: '#e0e0e0', + gray100: '#f0f0f0', + white: '#fff', +}; + +const MISC_COLORS = { + darkThemeFocus: get( 'white' ), + darkGrayPlaceholder: rgba( GRAY_COLORS.gray900, 0.62 ), + mediumGrayPlaceholder: rgba( GRAY_COLORS.gray900, 0.55 ), + lightGrayPlaceholdeR: rgba( GRAY_COLORS.white, 0.65 ), +}; + +const ALERT_COLORS = { + alertYellow: '#f0b849', + alertRed: '#cc1818', + alertGreen: '#4ab866', +}; + const COLOR_PROPS = { - ...WORDPRESS_COLORS, - ...BACKGROUND_COLOR_PROPS, + ...GRAY_COLORS, + ...MISC_COLORS, + ...ALERT_COLORS, colorAdmin: '#007cba', colorDestructive: '#D94F4F', colorBodyBackground: get( 'white' ), - colorDivider: 'rgba(0, 0, 0, 0.1)', - colorPositive: get( 'greens' ), - colorScrollbarThumb: 'rgba(0, 0, 0, 0.2)', - colorScrollbarThumbHover: 'rgba(0, 0, 0, 0.5)', - colorScrollbarTrack: 'rgba(0, 0, 0, 0.04)', - colorText: '#1e1e1e', + colorText: get( 'gray900' ), colorTextInverted: get( 'white' ), colorTextHeading: '#050505', colorTextMuted: '#717171', - ...generateColorAdminColors( '#007cba' ), - ...generateColorDestructiveColors( '#D94F4F' ), }; const FONT_PROPS = { @@ -69,302 +72,12 @@ const FONT_PROPS = { fontWeightHeading: '600', }; -const SURFACE_PROPS = { - surfaceBackgroundColor: get( 'surfaceColor' ), - surfaceBackgroundSubtleColor: '#F3F3F3', - surfaceBackgroundTintColor: '#F5F5F5', - surfaceBorderColor: 'rgba(0, 0, 0, 0.1)', - surfaceBorderBoldColor: 'rgba(0, 0, 0, 0.15)', - surfaceBorderSubtleColor: 'rgba(0, 0, 0, 0.05)', - surfaceBackgroundTertiaryColor: '#ffffff', - surfaceColor: get( 'white' ), -}; - -const ELEVATION_PROPS = { - elevationIntensity: 1, -}; - -const GRID_PROPS = { - gridBase: '4px', -}; - -const CONTROL_PROPS = { - controlBackgroundColor: get( 'white' ), - controlBackgroundColorHover: 'rgba(0, 0, 0, 0.05)', - controlBackgroundColorActive: 'rgba(0, 0, 0, 0.05)', - controlBackgroundDimColor: 'rgba(0, 0, 0, 0.1)', - controlBackgroundBrightColor: 'rgba(0, 0, 0, 0.03)', - controlBorderColor: '#757575', - controlBorderColorHover: get( 'controlBorderColor' ), - controlBorderColorSubtle: 'transparent', - controlBorderRadius: '2px', - controlBorderSubtleColor: 'rgba(0, 0, 0, 0.2)', - controlBoxShadowFocusSize: '0.5px', - controlBoxShadow: `transparent`, - controlBoxShadowFocus: flow( - '0 0 0', - get( 'controlBoxShadowFocusSize' ), - get( 'colorAdmin' ) - ), - controlPseudoBoxShadowFocusWidth: '2px', - controlPseudoBoxShadowFocusRingSize: flow.calc( - get( 'controlPseudoBoxShadowFocusWidth' ), - '+ 1px +', - get( 'controlBoxShadowFocusSize' ) - ), - controlPseudoBoxShadowFocusRingSizeSmall: flow.calc( - get( 'controlPseudoBoxShadowFocusWidth' ), - '+ 1px' - ), - controlPseudoBoxShadowFocus: flow( - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusWidth' ), - get( 'surfaceBackgroundColor' ), - ], - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusRingSize' ), - get( 'colorAdmin' ), - ] - ), - controlPseudoBoxShadowFocusSmall: flow( - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusWidth' ), - get( 'surfaceBackgroundColor' ), - ], - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusRingSizeSmall' ), - get( 'colorAdmin' ), - ] - ), - controlDestructivePseudoBoxShadowFocus: flow( - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusWidth' ), - get( 'surfaceBackgroundColor' ), - ], - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusRingSize' ), - get( 'colorDestructive' ), - ] - ), - controlDestructivePseudoBoxShadowFocusSmall: flow( - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusWidth' ), - get( 'surfaceBackgroundColor' ), - ], - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusRingSizeSmall' ), - get( 'colorDestructive' ), - ] - ), - controlDestructiveBorderColor: get( 'colorDestructive' ), - controlDestructiveBorderColorFocus: get( 'controlDestructiveBorderColor' ), - controlDestructiveBoxShadowFocus: flow( - '0 0 0', - get( 'controlBoxShadowFocusSize' ), - get( 'colorDestructive' ) - ), - controlHeight: '30px', - controlHeightLarge: `calc(${ get( 'controlHeight' ) } * 1.2)`, - controlHeightSmall: `calc(${ get( 'controlHeight' ) } * 0.8)`, - controlHeightXLarge: `calc(${ get( 'controlHeight' ) } * 1.4)`, - controlHeightXSmall: `calc(${ get( 'controlHeight' ) } * 0.67)`, - controlHeightXXSmall: `calc(${ get( 'controlHeight' ) } * 0.4)`, - controlPaddingX: '12px', - controlPaddingXLarge: `calc(${ get( 'controlPaddingX' ) } * 1.3334)`, - controlPaddingXSmall: `calc(${ get( 'controlPaddingX' ) } / 1.3334)`, - controlPrimaryTextColorActive: get( 'white' ), - controlPrimaryTextColor: get( 'white' ), - controlSurfaceBoxShadow: flow( - [ '0 1px 1px rgba(0, 0, 0, 0.2)' ], - [ '0 1px 2px rgba(0, 0, 0, 0.2)' ] - ), - controlSurfaceColor: get( 'white' ), - controlTextActiveColor: get( 'colorAdmin' ), - controlInnerControltextColor: get( 'colorAdmin' ), -}; - -const BUTTON_PROPS = { - buttonPaddingXRatio: 'calc(4/3)', - buttonPaddingX: flow.calc( - get( 'controlPaddingX' ), - '*', - get( 'buttonPaddingXRatio' ) - ), - - buttonTextColor: get( 'colorAdmin' ), - buttonTextColorActive: get( 'buttonTextColor' ), - - buttonPrimaryColor: get( 'colorAdmin' ), - buttonPrimaryColorHover: get( 'buttonPrimaryColor' ), - buttonPrimaryColorActive: get( 'colorText' ), - buttonPrimaryColorFocus: get( 'buttonPrimaryColor' ), - buttonPrimaryBorderColor: get( 'buttonPrimaryColor' ), - buttonPrimaryBorderColorHover: get( 'buttonPrimaryColor' ), - buttonPrimaryBorderColorFocus: get( 'buttonPrimaryColor' ), - buttonPrimaryBorderColorActive: get( 'buttonPrimaryColor' ), - buttonPrimaryTextColor: get( 'controlPrimaryTextColor' ), - buttonPrimaryTextColorHover: get( 'controlPrimaryTextColor' ), - buttonPrimaryTextColorActive: get( 'controlPrimaryTextColor' ), - buttonPrimaryTextColorFocus: get( 'controlPrimaryTextColor' ), - - buttonSecondaryColor: 'transparent', - buttonSecondaryColorHover: get( 'buttonSecondaryColor' ), - buttonSecondaryColorActive: 'rgba(0, 0, 0, 0.05)', - buttonSecondaryColorFocus: get( 'buttonSecondaryColor' ), - buttonSecondaryBorderColor: get( 'buttonPrimaryColor' ), - buttonSecondaryTextColor: get( 'buttonPrimaryColor' ), - buttonSecondaryTextColorFocus: get( 'buttonPrimaryColor' ), - buttonSecondaryTextColorActive: get( 'buttonPrimaryColor' ), - buttonSecondaryBorderColorHover: get( 'buttonPrimaryColor' ), - buttonSecondaryBorderColorActive: get( 'buttonPrimaryColor' ), - buttonSecondaryBorderColorFocus: get( 'buttonPrimaryColor' ), - - buttonTertiaryColor: 'transparent', - buttonTertiaryColorHover: get( 'buttonTertiaryColor' ), - buttonTertiaryColorActive: 'rgba(0, 0, 0, 0.05)', - buttonTertiaryColorFocus: get( 'buttonTertiaryColor' ), - buttonTertiaryBorderColor: 'transparent', - buttonTertiaryTextColor: get( 'buttonPrimaryColor' ), - buttonTertiaryTextColorFocus: get( 'buttonPrimaryColor' ), - buttonTertiaryTextColorActive: get( 'buttonPrimaryColor' ), - buttonTertiaryBorderColorHover: get( 'buttonPrimaryColor' ), - buttonTertiaryBorderColorActive: get( 'buttonPrimaryColor' ), - buttonTertiaryBorderColorFocus: get( 'buttonPrimaryColor' ), - - buttonControlActiveStateColor: get( 'colorText' ), - buttonControlActiveStateColorHover: get( 'buttonControlActiveStateColor' ), - buttonControlActiveStateColorActive: get( 'buttonControlActiveStateColor' ), - buttonControlActiveStateColorFocus: get( 'buttonControlActiveStateColor' ), - buttonControlActiveStateTextColor: get( 'buttonPrimaryTextColor' ), - buttonControlActiveStateBorderColorFocus: get( 'buttonPrimaryColor' ), - buttonControlActiveStateBoxShadowFocus: flow( - [ '0 0 0', get( 'controlBoxShadowFocusSize' ), get( 'colorAdmin' ) ], - [ - '0 0 0', - get( 'controlPseudoBoxShadowFocusWidth' ), - get( 'buttonControlActiveStateTextColor' ), - 'inset', - ] - ), -}; - -const CARD_PROPS = { - cardBorderRadius: '2px', - cardPaddingX: space( 3 ), - cardPaddingY: space( 3 ), - cardPadding: flow( get( 'cardPaddingX' ), get( 'cardPaddingY' ) ), - cardHeaderFooterPaddingY: space( 1 ), - cardHeaderHeight: '44px', -}; - -const CHECKBOX_PROPS = { - checkboxBoxShadow: 'none', - checkboxSize: '16px', -}; - -const FLEX_PROPS = { - flexGap: space( 2 ), - flexItemMarginRight: get( 'flexGap' ), -}; - -const LINK_PROPS = { - linkColor: get( 'colorAdmin' ), - linkColorHover: get( 'colorAdmin' ), - linkColorActive: get( 'colorAdmin' ), - linkColorFocus: get( 'colorAdmin' ), -}; - -const MENU_PROPS = { - menuItemBorderWidth: '1px', - menuItemFocusBackgroundColor: 'transparent', - menuItemFocusBorderColor: get( 'colorAdmin' ), - menuItemFocusTextColor: get( 'menuItemFocusBorderColor' ), - menuItemFocusBoxShadow: get( 'controlBorderSubtleColor' ), - menuItemActiveBackgroundColor: get( 'controlBackgroundColor' ), - menuItemActiveBorderColor: get( 'menuItemFocusBorderColor' ), - menuItemActiveTextColor: get( 'colorText' ), - menuItemActiveBoxShadow: get( 'controlBorderSubtleColor' ), - menuItemHeight: '30px', - menuItemHeightLarge: `calc(${ get( 'menuItemHeight' ) } * 1.2)`, - menuItemHeightSmall: `calc(${ get( 'menuItemHeight' ) } * 0.8)`, - menuItemHeightXLarge: `calc(${ get( 'menuItemHeight' ) } * 1.4)`, - menuItemHeightXSmall: `calc(${ get( 'menuItemHeight' ) } * 0.67)`, - menuItemHeightXXSmall: `calc(${ get( 'menuItemHeight' ) } * 0.4)`, -}; - -const PANEL_PROPS = { - panelHeaderPadding: `${ space( 3 ) } ${ space( 4 ) }`, - panelBodyPadding: `${ space( 2 ) } ${ space( 4 ) } ${ space( 3 ) }`, -}; - -const RADIO_PROPS = { - radioBoxShadow: get( 'checkboxBoxShadow' ), - radioSize: get( 'checkboxSize' ), - radioDotSize: '10px', -}; - -const SEGMENTED_CONTROL_PROPS = { - segmentedControlFontSize: '12px', - segmentedControlBackgroundColor: get( 'controlBackgroundColor' ), - segmentedControlBorderColor: get( 'controlBorderColor' ), - segmentedControlBackdropBackgroundColor: get( 'controlSurfaceColor' ), - segmentedControlBackdropBorderColor: get( 'controlBorderColor' ), - segmentedControlBackdropBoxShadow: 'transparent', - segmentedControlButtonColorActive: get( 'controlBackgroundColor' ), -}; - -const SLIDER_PROPS = { - sliderThumbBorderColor: 'transparent', - sliderThumbBoxShadow: 'none', - sliderThumbBoxShadowSizeFocus: '3px', - sliderThumbBoxShadowColorFocus: get( 'colorAdminRgba20' ), - sliderThumbBackgroundColor: get( 'colorAdmin' ), -}; - -const SWITCH_PROPS = { - switchBackdropBackgroundColor: get( 'lightGray900' ), - switchBackdropBackgroundColorActive: get( 'colorAdmin' ), - switchBackdropBorderColor: get( 'lightGray900' ), - switchBackdropBorderColorActive: get( 'colorAdmin' ), - switchBackdropBorderColorFocus: get( 'white' ), - switchToggleBackgroundColor: get( 'colorTextInverted' ), - switchToggleBackgroundColorActive: get( 'colorTextInverted' ), - switchToggleBoxShadow: 'none', - switchPaddingOffset: '6px', -}; - const BASE_THEME = { - // Colors - ...G2_COLORS, ...COLOR_PROPS, // Base - ...CARD_PROPS, - ...CONTROL_PROPS, - ...ELEVATION_PROPS, - ...FLEX_PROPS, ...FONT_PROPS, - ...SURFACE_PROPS, // Animations ...ANIMATION_PROPS, - // The Rest - ...BUTTON_PROPS, - ...CHECKBOX_PROPS, - ...GRID_PROPS, - ...LINK_PROPS, - ...MENU_PROPS, - ...PANEL_PROPS, - ...RADIO_PROPS, - ...SEGMENTED_CONTROL_PROPS, - ...SLIDER_PROPS, - ...SWITCH_PROPS, }; export const config = BASE_THEME; diff --git a/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js b/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js index 8ffcc7aa98260..146f5b7ce671f 100644 --- a/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js +++ b/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js @@ -1,7 +1 @@ -export const darkHighContrastModeConfig = { - colorDivider: '#eee', - controlBorderColor: '#eee', - controlBorderColorHover: '#eee', - controlBorderColorSubtle: '#eee', - surfaceBorderColor: '#eee', -}; +export const darkHighContrastModeConfig = {}; diff --git a/packages/components/src/ui/styles/theme/dark-mode-config.js b/packages/components/src/ui/styles/theme/dark-mode-config.js index 72778f9b70ece..94f77716b986a 100644 --- a/packages/components/src/ui/styles/theme/dark-mode-config.js +++ b/packages/components/src/ui/styles/theme/dark-mode-config.js @@ -1,14 +1,4 @@ -/** - * Internal dependencies - */ -import { get } from '../../create-styles'; -import { DARK_MODE_COLORS, DARK_MODE_RGBA_COLORS } from './tokens'; - const DARK_MODE_PROPS = { - ...DARK_MODE_COLORS, - ...DARK_MODE_RGBA_COLORS, - buttonPrimaryTextColorActive: get( 'controlPrimaryTextColorActive' ), - buttonControlActiveStateTextColor: get( 'colorTextInverted' ), colorBodyBackground: '#18191A', colorDivider: 'rgba(255, 255, 255, 0.1)', colorScrollbarThumb: 'rgba(255, 255, 255, 0.2)', @@ -18,27 +8,6 @@ const DARK_MODE_PROPS = { colorTextMuted: '#7a7a7a', colorTextInverted: '#050505', colorTextHeading: '#ffffff', - controlBackgroundColor: get( 'colorBodyBackground' ), - controlBackgroundColorHover: 'rgba(255, 255, 255, 0.3)', - controlBackgroundBrightColor: 'rgba(255, 255, 255, 0.08)', - controlBackgroundDimColor: 'rgba(255, 255, 255, 0.2)', - controlBorderSubtleColor: 'rgba(255, 255, 255, 0.5)', - controlPrimaryTextColorActive: get( 'black' ), - controlPrimaryTextColor: get( 'white' ), - controlSurfaceColor: 'rgba(255, 255, 255, 0.3)', - controlTextActiveColor: get( 'white' ), - surfaceBackgroundColor: get( 'colorBodyBackground' ), - surfaceBackgroundSubtleColor: '#151515', - surfaceBackgroundTintColor: '#252525', - surfaceBackgroundTertiaryColor: '#000', - surfaceBorderColor: 'rgba(255, 255, 255, 0.1)', - surfaceBorderBoldColor: 'rgba(255, 255, 255, 0.15)', - surfaceBorderSubtleColor: 'rgba(255, 255, 255, 0.05)', - surfaceColor: '#292929', -}; - -export const DARK_THEME = { - ...DARK_MODE_PROPS, }; -export const darkModeConfig = DARK_THEME; +export const darkModeConfig = DARK_MODE_PROPS; diff --git a/packages/components/src/ui/styles/theme/theme.js b/packages/components/src/ui/styles/theme/theme.js index 5851aeacfa1ee..9d2e82ad11a00 100644 --- a/packages/components/src/ui/styles/theme/theme.js +++ b/packages/components/src/ui/styles/theme/theme.js @@ -2,30 +2,3 @@ export { config } from './config'; export { darkModeConfig } from './dark-mode-config'; export { highContrastModeConfig } from './high-contrast-mode-config'; export { darkHighContrastModeConfig } from './dark-high-contrast-mode-config'; - -/* eslint-disable jsdoc/valid-types */ -/** - * @typedef { - | 'blue' - | 'red' - | 'purple' - | 'green' - | 'yellow' - | 'orange' - | 'darkGray' - | 'lightGray' - } SupportedColors - */ -/* eslint-enable jsdoc/valid-types */ - -/** @type {SupportedColors[]} */ -export const SUPPORTED_COLORS = [ - 'blue', - 'red', - 'purple', - 'green', - 'yellow', - 'orange', - 'darkGray', - 'lightGray', -]; diff --git a/packages/components/src/ui/styles/theme/tokens/colors.js b/packages/components/src/ui/styles/theme/tokens/colors.js deleted file mode 100644 index 9c996cdaa95cf..0000000000000 --- a/packages/components/src/ui/styles/theme/tokens/colors.js +++ /dev/null @@ -1,206 +0,0 @@ -/** - * Internal dependencies - */ -import { get } from '../../../create-styles'; -import { createRgbaColors, createTextColors } from '../utils'; - -export const CORE_PURPLE_COLORS = { - purple100: '#f3f1f8', - purple300: '#B4A8D2', - purple500: '#826eb4', - purple700: '#4e426c', - purple900: '#342c48', -}; - -export const CORE_DARK_GRAY_COLORS = { - darkGray100: '#8F98A1', - darkGray300: '#6C7781', - darkGray500: '#555D66', - darkGray700: '#32373C', - darkGray900: '#191E23', -}; - -export const CORE_LIGHT_GRAY_COLORS = { - lightGray100: '#fbfbfc', - lightGray300: '#edeff0', - lightGray500: '#e2e4e7', - lightGray700: '#ccd0d4', - lightGray900: '#a2aab2', -}; - -export const CORE_RED_COLORS = { - red100: '#fcebeb', - red300: '#ea8484', - red500: '#dc3232', - red700: '#b02828', - red900: '#841e1e', -}; - -export const CORE_ORANGE_COLORS = { - orange100: '#fef1ea', - orange300: '#f9a87e', - orange500: '#F56E28', - orange700: '#ca4a1f', - orange900: '#aa3e1a', -}; - -export const CORE_YELLOW_COLORS = { - yellow100: '#fff8e6', - yellow300: '#ffd566', - yellow500: '#ffb900', - yellow700: '#ee8e0d', - yellow900: '#dd631a', -}; - -export const CORE_GREEN_COLORS = { - green100: '#edf8ee', - green300: '#90d296', - green500: '#46b450', - green700: '#328540', - green900: '#25612f', -}; - -export const CORE_BLUE_COLORS = { - blue100: '#e6f6fb', - blue300: '#66c6e4', - blue500: '#00a0d2', - blue700: '#0085ba', - blue900: '#0072A8', -}; - -export const DARK_GRAY_COLORS = { - ...CORE_DARK_GRAY_COLORS, - ...createTextColors( CORE_DARK_GRAY_COLORS ), - ...createRgbaColors( CORE_DARK_GRAY_COLORS ), -}; - -export const LIGHT_GRAY_COLORS = { - ...CORE_LIGHT_GRAY_COLORS, - ...createTextColors( CORE_LIGHT_GRAY_COLORS ), - ...createRgbaColors( CORE_LIGHT_GRAY_COLORS ), -}; - -export const RED_COLORS = { - ...CORE_RED_COLORS, - ...createTextColors( CORE_RED_COLORS ), - ...createRgbaColors( CORE_RED_COLORS ), -}; - -export const ORANGE_COLORS = { - ...CORE_ORANGE_COLORS, - ...createTextColors( CORE_ORANGE_COLORS ), - ...createRgbaColors( CORE_ORANGE_COLORS ), -}; - -export const YELLOW_COLORS = { - ...CORE_YELLOW_COLORS, - ...createTextColors( CORE_YELLOW_COLORS ), - ...createRgbaColors( CORE_YELLOW_COLORS ), -}; - -export const GREEN_COLORS = { - ...CORE_GREEN_COLORS, - ...createTextColors( CORE_GREEN_COLORS ), - ...createRgbaColors( CORE_GREEN_COLORS ), -}; - -export const PURPLE_COLORS = { - ...CORE_PURPLE_COLORS, - ...createTextColors( CORE_PURPLE_COLORS ), - ...createRgbaColors( CORE_PURPLE_COLORS ), -}; - -export const BLUE_COLORS = { - ...CORE_BLUE_COLORS, - ...createTextColors( CORE_BLUE_COLORS ), - ...createRgbaColors( CORE_BLUE_COLORS ), -}; - -export const WORDPRESS_COLORS = { - ...DARK_GRAY_COLORS, - ...LIGHT_GRAY_COLORS, - ...RED_COLORS, - ...ORANGE_COLORS, - ...YELLOW_COLORS, - ...GREEN_COLORS, - ...PURPLE_COLORS, - ...BLUE_COLORS, -}; - -export const G2_COLORS = { - black: '#000000', - blueberry: '#3858E9', - blueberryDark: '#1D35B4', - greens: '#33F078', - grey: '#40464D', - greyBlack: '#1E1E1E', - lightBlue: '#33F078', - lightGrey: '#40464D', - lighterGrey: '#dddddd', - pomegrade: '#E26F56', - wordpressBlue: '#007cba', - white: '#ffffff', -}; - -export const BACKGROUND_COLOR_PROPS = { - colorBackgroundBlue: get( 'blueRgba10' ), - colorBackgroundBlueText: get( 'blue900' ), - - colorBackgroundDarkGray: get( 'darkGrayRgba10' ), - colorBackgroundDarkGrayText: get( 'darkGray900' ), - - colorBackgroundGreen: get( 'greenRgba10' ), - colorBackgroundGreenText: get( 'green900' ), - - colorBackgroundLightGray: get( 'lightGrayRgba10' ), - colorBackgroundLightGrayText: get( 'lightGray900' ), - - colorBackgroundOrange: get( 'orangeRgba10' ), - colorBackgroundOrangeText: get( 'orange900' ), - - colorBackgroundPurple: get( 'purpleRgba10' ), - colorBackgroundPurpleText: get( 'purple900' ), - - colorBackgroundRed: get( 'redRgba10' ), - colorBackgroundRedText: get( 'red900' ), - - colorBackgroundYellow: get( 'yellowRgba10' ), - colorBackgroundYellowText: get( 'yellow900' ), -}; - -export const DARK_MODE_COLORS = { - colorBackgroundBlue: get( 'blueRgba20' ), - colorBackgroundBlueText: get( 'blue300' ), - - colorBackgroundDarkGray: get( 'darkGrayRgba20' ), - colorBackgroundDarkGrayText: get( 'white' ), - - colorBackgroundGreen: get( 'greenRgba20' ), - colorBackgroundGreenText: get( 'green300' ), - - colorBackgroundLightGray: get( 'lightGrayRgba20' ), - colorBackgroundLightGrayText: get( 'white' ), - - colorBackgroundOrange: get( 'orangeRgba20' ), - colorBackgroundOrangeText: get( 'orange300' ), - - colorBackgroundPurple: get( 'purpleRgba20' ), - colorBackgroundPurpleText: get( 'purple300' ), - - colorBackgroundRed: get( 'redRgba20' ), - colorBackgroundRedText: get( 'red300' ), - - colorBackgroundYellow: get( 'yellowRgba20' ), - colorBackgroundYellowText: get( 'yellow300' ), -}; - -export const DARK_MODE_RGBA_COLORS = { - ...createRgbaColors( CORE_BLUE_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_GREEN_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_ORANGE_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_PURPLE_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_RED_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_YELLOW_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_DARK_GRAY_COLORS, /* isDark */ true ), - ...createRgbaColors( CORE_LIGHT_GRAY_COLORS, /* isDark */ true ), -}; diff --git a/packages/components/src/ui/styles/theme/tokens/index.js b/packages/components/src/ui/styles/theme/tokens/index.js deleted file mode 100644 index 1bae1c0e497ca..0000000000000 --- a/packages/components/src/ui/styles/theme/tokens/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './colors'; From e2fa2c3fb7ed50085edd8367125f73f9bc46355e Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Tue, 13 Apr 2021 05:32:49 -0700 Subject: [PATCH 11/19] Fix gridBase no longer existing in get --- packages/components/src/ui/styles/config.js | 3 +++ packages/components/src/ui/styles/mixins/space.js | 4 ++-- .../src/ui/styles/theme/dark-mode-config.js | 4 ---- packages/components/src/ui/styles/theme/utils.js | 12 ------------ 4 files changed, 5 insertions(+), 18 deletions(-) create mode 100644 packages/components/src/ui/styles/config.js diff --git a/packages/components/src/ui/styles/config.js b/packages/components/src/ui/styles/config.js new file mode 100644 index 0000000000000..d68279558cbd7 --- /dev/null +++ b/packages/components/src/ui/styles/config.js @@ -0,0 +1,3 @@ +export const VARS = { + gridBase: '4px', +}; diff --git a/packages/components/src/ui/styles/mixins/space.js b/packages/components/src/ui/styles/mixins/space.js index e17900a7e1558..19d4451b0eb34 100644 --- a/packages/components/src/ui/styles/mixins/space.js +++ b/packages/components/src/ui/styles/mixins/space.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { get } from '../core'; +import { VARS } from '../config'; /** * @param {import('react').ReactText} value @@ -9,6 +9,6 @@ import { get } from '../core'; */ export function space( value ) { return typeof value === 'number' - ? `calc(${ get( 'gridBase' ) } * ${ value })` + ? `calc(${ VARS.gridBase } * ${ value })` : value; } diff --git a/packages/components/src/ui/styles/theme/dark-mode-config.js b/packages/components/src/ui/styles/theme/dark-mode-config.js index 94f77716b986a..bc7e1a8db6d72 100644 --- a/packages/components/src/ui/styles/theme/dark-mode-config.js +++ b/packages/components/src/ui/styles/theme/dark-mode-config.js @@ -1,9 +1,5 @@ const DARK_MODE_PROPS = { colorBodyBackground: '#18191A', - colorDivider: 'rgba(255, 255, 255, 0.1)', - colorScrollbarThumb: 'rgba(255, 255, 255, 0.2)', - colorScrollbarThumbHover: 'rgba(255, 255, 255, 0.5)', - colorScrollbarTrack: 'rgba(0, 0, 0, 0.04)', colorText: '#E4E6EB', colorTextMuted: '#7a7a7a', colorTextInverted: '#050505', diff --git a/packages/components/src/ui/styles/theme/utils.js b/packages/components/src/ui/styles/theme/utils.js index 700acd2e2e132..f6138eb9b6ba6 100644 --- a/packages/components/src/ui/styles/theme/utils.js +++ b/packages/components/src/ui/styles/theme/utils.js @@ -1,20 +1,8 @@ /** * External dependencies */ -/** - * Internal dependencies - */ -import { get } from '../../create-styles'; import colorize from 'tinycolor2'; -/** - * @param {number} value - * @return {string} Space. - */ -export function space( value ) { - return `calc(${ get( 'gridBase' ) } * ${ value })`; -} - /** * @param {Record} colors * @return {Record} Text colors. From 7f73cfe66c8e1d2e869d9aa31295518f3d0ab93d Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Tue, 13 Apr 2021 05:37:12 -0700 Subject: [PATCH 12/19] Rename vars to tokens --- packages/components/src/ui/styles/config.js | 3 --- packages/components/src/ui/styles/mixins/space.js | 4 ++-- packages/components/src/ui/styles/theme/config.js | 4 +--- packages/components/src/ui/styles/theme/dark-mode-config.js | 4 +--- packages/components/src/ui/styles/tokens.js | 3 +++ packages/components/src/ui/styles/ui.js | 2 ++ 6 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 packages/components/src/ui/styles/config.js create mode 100644 packages/components/src/ui/styles/tokens.js diff --git a/packages/components/src/ui/styles/config.js b/packages/components/src/ui/styles/config.js deleted file mode 100644 index d68279558cbd7..0000000000000 --- a/packages/components/src/ui/styles/config.js +++ /dev/null @@ -1,3 +0,0 @@ -export const VARS = { - gridBase: '4px', -}; diff --git a/packages/components/src/ui/styles/mixins/space.js b/packages/components/src/ui/styles/mixins/space.js index 19d4451b0eb34..ad5765a0203bb 100644 --- a/packages/components/src/ui/styles/mixins/space.js +++ b/packages/components/src/ui/styles/mixins/space.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { VARS } from '../config'; +import { tokens } from '../tokens'; /** * @param {import('react').ReactText} value @@ -9,6 +9,6 @@ import { VARS } from '../config'; */ export function space( value ) { return typeof value === 'number' - ? `calc(${ VARS.gridBase } * ${ value })` + ? `calc(${ tokens.gridBase } * ${ value })` : value; } diff --git a/packages/components/src/ui/styles/theme/config.js b/packages/components/src/ui/styles/theme/config.js index d8f94f0ed0f01..5cb601e08c9e3 100644 --- a/packages/components/src/ui/styles/theme/config.js +++ b/packages/components/src/ui/styles/theme/config.js @@ -72,12 +72,10 @@ const FONT_PROPS = { fontWeightHeading: '600', }; -const BASE_THEME = { +export const config = { ...COLOR_PROPS, // Base ...FONT_PROPS, // Animations ...ANIMATION_PROPS, }; - -export const config = BASE_THEME; diff --git a/packages/components/src/ui/styles/theme/dark-mode-config.js b/packages/components/src/ui/styles/theme/dark-mode-config.js index bc7e1a8db6d72..6ca5321a90f22 100644 --- a/packages/components/src/ui/styles/theme/dark-mode-config.js +++ b/packages/components/src/ui/styles/theme/dark-mode-config.js @@ -1,9 +1,7 @@ -const DARK_MODE_PROPS = { +export const darkModeConfig = { colorBodyBackground: '#18191A', colorText: '#E4E6EB', colorTextMuted: '#7a7a7a', colorTextInverted: '#050505', colorTextHeading: '#ffffff', }; - -export const darkModeConfig = DARK_MODE_PROPS; diff --git a/packages/components/src/ui/styles/tokens.js b/packages/components/src/ui/styles/tokens.js new file mode 100644 index 0000000000000..2b25279c1f5a6 --- /dev/null +++ b/packages/components/src/ui/styles/tokens.js @@ -0,0 +1,3 @@ +export const tokens = Object.freeze( { + gridBase: '4px', +} ); diff --git a/packages/components/src/ui/styles/ui.js b/packages/components/src/ui/styles/ui.js index b7b244db3e08b..d11fad5bfa5d2 100644 --- a/packages/components/src/ui/styles/ui.js +++ b/packages/components/src/ui/styles/ui.js @@ -3,8 +3,10 @@ */ import { get } from './core'; import { space } from './mixins'; +import { tokens } from './tokens'; export const ui = { get, space, + tokens, }; From 2e944f4976525b54569bee3804032dd7adfca4bf Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Tue, 13 Apr 2021 05:51:09 -0700 Subject: [PATCH 13/19] Add README and do further cleanup --- packages/components/src/ui/styles/README.md | 61 +++++++++++++++++++ .../components/src/ui/styles/presets/flow.js | 17 ------ packages/components/src/ui/styles/ui.js | 3 +- 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 packages/components/src/ui/styles/README.md delete mode 100644 packages/components/src/ui/styles/presets/flow.js diff --git a/packages/components/src/ui/styles/README.md b/packages/components/src/ui/styles/README.md new file mode 100644 index 0000000000000..41c09cfe96f2b --- /dev/null +++ b/packages/components/src/ui/styles/README.md @@ -0,0 +1,61 @@ +# styles + +## The `ui` object + +The primary API that `styles` exposes is the `ui` object. It contains the following properties: + +- `get`: Retrieves a pre-defined set of CSS Custom Properties. See [Theme Configuration](#theme-configuration) below. +- `tokens`: A pre-defined set of theme variables, accessible via the frozen `tokens` object. See [Theme Tokens](#theme-tokens) below. +- Various mixins. See [Mixins](#mixins) below. + +## Theme Configuration + +Each of the configs declares overrides for the theme variables. The overall list of available theme variables is declared in [`styles/theme/config.js`](./theme/config.js). Individual overrides can be found in [`styles/theme/dark-mode-config.js`](./theme/dark-mode-config.js), [`styles/theme/high-contrast-mode-config.js`](./theme/high-contrast-mode-config.js), and [`styles/theme/dark-high-contrast-mode-config.js`](./theme/dark-high-contrast-mode-config.js). + +Variables added to the overarching config should align with variables declared in the `base-styles` package. + +These variables are accessed via the `ui.get` helper exported from `styles` and are exposed as CSS Custom Properties. + +## Theme Tokens + +Tokens are similar to variables except that they are not exposed as CSS Custom Properties. This is to avoid introducing too many new public APIs. Instead, we simply access them off of the `ui.tokens` object as you would any normal JavaScript object. `ui.tokens` is a _frozen_ object so runtime changes are no allowed to it, updates to it must be constant and done in the [`styles/tokens.js`](./tokens.js) module. + +## Mixins + +Mixins are helper functions for composing and building styles. + +### `space` + +`space` is the core of the style system's spacing system. It will automatically transform a given space value into the correct spacing for the theme based off the token `gridBase` value. It can accept any number value. + +### `flow` + +Combines CSS values. Useful for complex shorthand values, functions (e.g. calc()), and mixed string/JS values. + + +```js +const boxShadow = flow( + '0 1px', + get( 'gray900' ), + '2px', + get('gray400') +) +``` + +#### Combining groups + +Groups (`Array`) can be passed into `flow()`, which re combined and comma separated. Useful for compounded CSS values (e.g. box-shadow`). + +```js +const boxShadow = flow( [ + '0 1px', + get( 'gray900' ), + '2px', + get( 'gray400' ) +], [ + '0 10px', + get( 'gray900' ), + '20px', + get( 'gray300' ) +] ); +``` diff --git a/packages/components/src/ui/styles/presets/flow.js b/packages/components/src/ui/styles/presets/flow.js deleted file mode 100644 index ffbe577125ee7..0000000000000 --- a/packages/components/src/ui/styles/presets/flow.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Internal dependencies - */ -import { flow as baseFlow } from '../mixins/flow'; - -/* eslint-disable jsdoc/valid-types */ -/** - * @type {{ - (...args: (string|string[])[]): string; - calc: (...args: (string|string[])[]) => string; -}} - */ -/* eslint-enable jsdoc/valid-types */ -// @ts-ignore We add calc below -export const flow = baseFlow; - -flow.calc = ( ...args ) => `calc(${ baseFlow( ...args ) })`; diff --git a/packages/components/src/ui/styles/ui.js b/packages/components/src/ui/styles/ui.js index d11fad5bfa5d2..680e591beee00 100644 --- a/packages/components/src/ui/styles/ui.js +++ b/packages/components/src/ui/styles/ui.js @@ -2,11 +2,12 @@ * Internal dependencies */ import { get } from './core'; -import { space } from './mixins'; +import { space, flow } from './mixins'; import { tokens } from './tokens'; export const ui = { get, space, + flow, tokens, }; From 5f2107cc007865d44248ea0d87af07bfb3bb3016 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Fri, 16 Apr 2021 10:34:33 -0700 Subject: [PATCH 14/19] Clean up and add hooks README --- .../create-styles/create-compiler/README.md | 2 + .../src/ui/styles/components/box.js | 4 +- .../components/src/ui/styles/hooks/README.md | 47 +++++++++++++++++++ .../components/src/ui/styles/hooks/index.js | 1 - .../components/src/ui/styles/hooks/use-rtl.js | 6 --- packages/components/src/ui/styles/index.js | 5 +- 6 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 packages/components/src/ui/styles/hooks/README.md delete mode 100644 packages/components/src/ui/styles/hooks/use-rtl.js diff --git a/packages/components/src/ui/create-styles/create-compiler/README.md b/packages/components/src/ui/create-styles/create-compiler/README.md index 76773b7a2ca1d..ac5b3acfe343d 100644 --- a/packages/components/src/ui/create-styles/create-compiler/README.md +++ b/packages/components/src/ui/create-styles/create-compiler/README.md @@ -14,6 +14,8 @@ css({ This will dynamically respond to breakpoints and render the appropriate width for each `min-width`. The breakpoints are documented in the code in [`utils.js`](./utils.js). + + ## Plugins `createCompiler` supports passing certain parameters to plugins. Plugin initialization should be contained to [`plugins/index.js`](./plugins/index.js). diff --git a/packages/components/src/ui/styles/components/box.js b/packages/components/src/ui/styles/components/box.js index e1897a4a39607..23711b7ed2f0b 100644 --- a/packages/components/src/ui/styles/components/box.js +++ b/packages/components/src/ui/styles/components/box.js @@ -3,6 +3,4 @@ */ import { core } from '../core'; -export const Box = core.div; -export const BaseView = Box; -export const View = Box; +export const View = core.div; diff --git a/packages/components/src/ui/styles/hooks/README.md b/packages/components/src/ui/styles/hooks/README.md new file mode 100644 index 0000000000000..9e410b1a44c7b --- /dev/null +++ b/packages/components/src/ui/styles/hooks/README.md @@ -0,0 +1,47 @@ +# hooks + +## useResponsiveValue + +`useResponsiveValue` is a hook that allows a component to declare a responsive API. For example, if a component wishes to provide the ability to have its `size` prop be responsive, it would delcare the type as follows: + +```ts +type Size = 'small' | 'medium' | 'large'; + +interface Props { + size: Size | Size[] +} +``` + +Then the component itself will implement `useResponsiveValue`: + +```tsx +function Component( { size: sizeProp, className }: ViewOwnProps< Props, 'div' >, forwardedRef: Ref< any > ) { + const ref = useRef(); + + const size = useResponsiveValue( ref.current, sizeProp ); + + const classes = cx( + className, + size && styles.sizes[ size ] + ); + + return ( +
+ Code is Poetry! +
+ ); +} +``` + +This allows `size` to behave exactly as the "Breakpoint Values" as described by [`create-styles/create-compiler/README.md#breakpoint-values`](../../create-styles/create-compiler/README.md#breakpoint-values). + +That is, if a single size is passed in, it will be used. However if size is passed in as an array like so: + +```tsx + +``` + +Then the size corresponding to the given breakpoint will be used. See [`create-styles/create-compiler/README.md#breakpoint-values`](../../create-styles/create-compiler/README.md#breakpoint-values) for more details and examples. diff --git a/packages/components/src/ui/styles/hooks/index.js b/packages/components/src/ui/styles/hooks/index.js index 54063a0a647c4..2571f0e6e5e72 100644 --- a/packages/components/src/ui/styles/hooks/index.js +++ b/packages/components/src/ui/styles/hooks/index.js @@ -1,2 +1 @@ export * from './use-responsive-value'; -export * from './use-rtl'; diff --git a/packages/components/src/ui/styles/hooks/use-rtl.js b/packages/components/src/ui/styles/hooks/use-rtl.js deleted file mode 100644 index c4acaef0aa34d..0000000000000 --- a/packages/components/src/ui/styles/hooks/use-rtl.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @return {boolean} Whether the current document is RTL. - */ -export function useRTL() { - return document?.documentElement?.dir === 'rtl'; -} diff --git a/packages/components/src/ui/styles/index.js b/packages/components/src/ui/styles/index.js index 9224f012a98d8..1117b27c4c52a 100644 --- a/packages/components/src/ui/styles/index.js +++ b/packages/components/src/ui/styles/index.js @@ -1,8 +1,9 @@ export { css } from './css'; +export { core } from './core'; export { cache, cx, injectGlobal, keyframes } from './style-system'; export { styled } from './styled'; -export { useResponsiveValue, useRTL } from './hooks'; +export { useResponsiveValue } from './hooks'; export { ui } from './ui'; /** @typedef {import('./components').StyleFrameProviderProps} StyleFrameProviderProps */ -export { StyleFrameProvider } from './components'; +export { StyleFrameProvider, View } from './components'; From 56f309e4a53cbe1e8159e9e2dddc7dbacb3b3bcc Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Mon, 19 Apr 2021 12:26:20 -0700 Subject: [PATCH 15/19] Remove modes from theme, renaming generate theme to be clearer about what it actually does now --- .../create-style-system/constants.js | 16 +--- .../create-core-element.js | 10 +-- .../create-core-elements.js | 2 +- .../create-css-custom-properties.js | 41 +++++++++ .../create-style-system.js | 36 ++------ .../create-styled-components.js | 6 +- .../create-style-system/generate-theme.js | 84 ------------------- .../hooks/use-hydrate-global-styles.js | 12 +-- packages/components/src/ui/styles/system.js | 12 +-- .../theme/dark-high-contrast-mode-config.js | 1 - .../src/ui/styles/theme/dark-mode-config.js | 7 -- .../styles/theme/high-contrast-mode-config.js | 7 -- .../components/src/ui/styles/theme/theme.js | 3 - 13 files changed, 59 insertions(+), 178 deletions(-) create mode 100644 packages/components/src/ui/create-styles/create-style-system/create-css-custom-properties.js delete mode 100644 packages/components/src/ui/create-styles/create-style-system/generate-theme.js delete mode 100644 packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js delete mode 100644 packages/components/src/ui/styles/theme/dark-mode-config.js delete mode 100644 packages/components/src/ui/styles/theme/high-contrast-mode-config.js diff --git a/packages/components/src/ui/create-styles/create-style-system/constants.js b/packages/components/src/ui/create-styles/create-style-system/constants.js index ca84e8336118c..73ac3a294d7ee 100644 --- a/packages/components/src/ui/create-styles/create-style-system/constants.js +++ b/packages/components/src/ui/create-styles/create-style-system/constants.js @@ -1,21 +1,7 @@ /** * Uses the the prefix for the CSS variables compiled by the system. */ -export const NAMESPACE = '--wp-experimental'; - -export const DARK_MODE_ATTR_PROP = 'data-system-ui-mode'; -export const HIGH_CONTRAST_MODE_ATTR_PROP = 'data-system-ui-contrast-mode'; -export const COLOR_BLIND_MODE_ATTR_PROP = 'data-system-ui-color-blind-mode'; -export const REDUCED_MOTION_MODE_ATTR_PROP = - 'data-system-ui-reduced-motion-mode'; - -export const DARK_MODE_ATTR = `[${ DARK_MODE_ATTR_PROP }="dark"]`; -export const HIGH_CONTRAST_MODE_MODE_ATTR = `[${ HIGH_CONTRAST_MODE_ATTR_PROP }="high"]`; - -export const COLOR_BLIND_MODE_ATTR = `[${ COLOR_BLIND_MODE_ATTR_PROP }="true"]`; -export const REDUCED_MOTION_MODE_ATTR = `[${ REDUCED_MOTION_MODE_ATTR_PROP }="true"]`; - -export const DARK_HIGH_CONTRAST_MODE_MODE_ATTR = `${ DARK_MODE_ATTR }${ HIGH_CONTRAST_MODE_MODE_ATTR }`; +export const NAMESPACE = '--wp-unstable'; export const MODE_SPECIFICITY_COMPOUND_LEVEL = 3; diff --git a/packages/components/src/ui/create-styles/create-style-system/create-core-element.js b/packages/components/src/ui/create-styles/create-style-system/create-core-element.js index 3ad94350b7bd6..34a6784a22bfb 100644 --- a/packages/components/src/ui/create-styles/create-style-system/create-core-element.js +++ b/packages/components/src/ui/create-styles/create-style-system/create-core-element.js @@ -8,10 +8,7 @@ import { forwardRef, createElement } from '@wordpress/element'; * Internal dependencies */ import { useHydrateGlobalStyles } from '../hooks'; -import { - INTERPOLATION_CLASS_NAME, - REDUCED_MOTION_MODE_ATTR, -} from './constants'; +import { INTERPOLATION_CLASS_NAME } from './constants'; import { DEFAULT_STYLE_SYSTEM_OPTIONS, getInterpolatedClassName, @@ -23,7 +20,7 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; * @typedef CreateCoreElementOptions * @property {import('create-emotion').ObjectInterpolation} baseStyles The baseStyles from the Style system. * @property {import('../create-compiler').Compiler} compiler The injectGlobal from the Style system's compiler. - * @property {import('./generate-theme').GenerateThemeResults} globalStyles The globalStyles from the Style system. + * @property {import('./create-css-custom-properties').CreateCSSCustomPropertiesResults} globalStyles The globalStyles from the Style system. */ /** @@ -69,9 +66,6 @@ export const createCoreElement = ( tagName, options ) => { @media ( prefers-reduced-motion ) { transition: none !important; } - ${ REDUCED_MOTION_MODE_ATTR } & { - transition: none !important; - } `, }; diff --git a/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js b/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js index 23a27aff0975c..d0464f230b09e 100644 --- a/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js +++ b/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js @@ -8,7 +8,7 @@ import { tags } from './tags'; * @typedef CreateCoreElementProps * @property {import('create-emotion').ObjectInterpolation} baseStyles Base styles for the coreElements. * @property {import('../create-compiler').Compiler} compiler The injectGlobal from the Style system's compiler. - * @property {import('./generate-theme').GenerateThemeResults} globalStyles Global styles for the coreElements. + * @property {import('./create-css-custom-properties').CreateCSSCustomPropertiesResults} globalStyles Global styles for the coreElements. */ /** diff --git a/packages/components/src/ui/create-styles/create-style-system/create-css-custom-properties.js b/packages/components/src/ui/create-styles/create-style-system/create-css-custom-properties.js new file mode 100644 index 0000000000000..10b296e0185ae --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/create-css-custom-properties.js @@ -0,0 +1,41 @@ +/** + * Internal dependencies + */ +import { + transformValuesToReferences, + transformValuesToVariables, + transformValuesToVariablesString, +} from './utils'; + +/** + * @typedef CreateCSSCustomPropertiesProps + * @property {import('./utils').StyleConfigValues} config Default theme config. + */ + +/** + * @typedef CreateCSSCustomPropertiesResults + * @property {import('./utils').StyleConfig} theme A set of theme style references. + * @property {import('./utils').StyleConfig} globalVariables A set of global variables. + * @property {string} globalCSSVariables The compiled CSS string for global variables. + */ + +/** + * Generates theme references and compiles CSS variables to be used by the Style System. + * + * @param {CreateCSSCustomPropertiesProps} props Props to generate a Style system theme with. + * @return {CreateCSSCustomPropertiesResults} A set of variables and content for the System. + */ +export function createCSSCustomProperties( { config = {} } ) { + const theme = transformValuesToReferences( config ); + const globalVariables = transformValuesToVariables( config ); + const globalCSSVariables = transformValuesToVariablesString( + ':root', + config + ); + + return { + theme, + globalVariables, + globalCSSVariables, + }; +} diff --git a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js index 5c437ed29adc7..51e47eefbdaf3 100644 --- a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js +++ b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js @@ -5,7 +5,7 @@ import { createCompiler } from '../create-compiler'; import { createCoreElement } from './create-core-element'; import { createCoreElements } from './create-core-elements'; import { createStyledComponents } from './create-styled-components'; -import { generateTheme } from './generate-theme'; +import { createCSSCustomProperties } from './create-css-custom-properties'; import { createToken, DEFAULT_STYLE_SYSTEM_OPTIONS } from './utils'; const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; @@ -13,9 +13,6 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; /* eslint-disable jsdoc/valid-types */ /** * @template {Record | {}} TConfig - * @template {Record | {}} TDarkConfig - * @template {Record | {}} THCConfig - * @template {Record | {}} TDarkHCConfig * @typedef CreateStyleSystemObjects * @property {import('./polymorphic-component').CoreElements} core A set of coreElements. * @property {import('../create-compiler').Compiler} compiler The Style system compiler (a custom Emotion instance). @@ -23,22 +20,16 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; * @property {import('../create-compiler').Compiler['css']} css A function to compile CSS styles. * @property {import('../create-compiler').Compiler['cx']} cx A function to resolve + combine classNames. * @property {(tokenName: string) => string} createToken A function to generate a design token (CSS variable) used by the system. - * @property {(value: keyof (TConfig & TDarkConfig & THCConfig & TDarkHCConfig)) => string} get The primary function to retrieve Style system variables. + * @property {(value: keyof TConfig) => string} get The primary function to retrieve Style system variables. * @property {import('./polymorphic-component').CreateStyled} styled A set of styled components. * @property {import('react').ComponentType} View The base component. */ /** * @template {Record | {}} TConfig - * @template {Record | {}} TDarkConfig - * @template {Record | {}} THCConfig - * @template {Record | {}} TDarkHCConfig * @typedef CreateStyleSystemOptions * @property {import('create-emotion').ObjectInterpolation} baseStyles The base styles. * @property {TConfig} config The base theme config. - * @property {TDarkConfig} darkModeConfig The dark mode theme config. - * @property {THCConfig} highContrastModeConfig The high contrast mode theme config. - * @property {TDarkHCConfig} darkHighContrastModeConfig The dark-high contrast mode theme config. * @property {import('../create-compiler').CreateCompilerOptions} [compilerOptions] The compiler options. */ /* eslint-enable jsdoc/valid-types */ @@ -53,30 +44,17 @@ const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; * ``` * * @template {Record | {}} TConfig - * @template {Record | {}} TDarkConfig - * @template {Record | {}} THCConfig - * @template {Record | {}} TDarkHCConfig - * @param {CreateStyleSystemOptions} options Options to create a Style system with. - * @return {CreateStyleSystemObjects} A collection of functions and elements from the generated Style system. + * @param {CreateStyleSystemOptions} options Options to create a Style system with. + * @return {CreateStyleSystemObjects} A collection of functions and elements from the generated Style system. */ export function createStyleSystem( options = defaultOptions ) { - const { - baseStyles, - compilerOptions, - config, - darkHighContrastModeConfig, - darkModeConfig, - highContrastModeConfig, - } = { + const { baseStyles, compilerOptions, config } = { ...defaultOptions, ...options, }; - const globalStyles = generateTheme( { + const globalStyles = createCSSCustomProperties( { config, - darkHighContrastModeConfig, - darkModeConfig, - highContrastModeConfig, } ); /** @@ -126,7 +104,7 @@ export function createStyleSystem( options = defaultOptions ) { cx, get: ( /* eslint-disable jsdoc/no-undefined-types */ - /** @type {keyof TConfig | keyof TDarkConfig | keyof THCConfig | keyof TDarkHCConfig} */ key + /** @type {keyof TConfig} */ key /* eslint-enable jsdoc/no-undefined-types */ ) => `var(${ createToken( key.toString() ) })`, styled, diff --git a/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js b/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js index ed28c959ccee7..1580a35bb23a5 100644 --- a/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js +++ b/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js @@ -38,9 +38,9 @@ export function createStyledComponents( { compiler, core } ) { const { css, cx, generateInterpolationName } = compiler; /** - * That's all a is :). A core.div. + * That's all a is :). A core.div. */ - const Box = core.div; + const View = core.div; /** * @@ -79,7 +79,7 @@ export function createStyledComponents( { compiler, core } ) { ); return ( - } */ +/** @type {import('../create-styles').CreateStyleSystemOptions} */ const systemConfig = { baseStyles: { MozOsxFontSmoothing: 'grayscale', @@ -21,9 +16,6 @@ const systemConfig = { margin: 0, }, config, - darkModeConfig, - highContrastModeConfig, - darkHighContrastModeConfig, }; export const { diff --git a/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js b/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js deleted file mode 100644 index 146f5b7ce671f..0000000000000 --- a/packages/components/src/ui/styles/theme/dark-high-contrast-mode-config.js +++ /dev/null @@ -1 +0,0 @@ -export const darkHighContrastModeConfig = {}; diff --git a/packages/components/src/ui/styles/theme/dark-mode-config.js b/packages/components/src/ui/styles/theme/dark-mode-config.js deleted file mode 100644 index 6ca5321a90f22..0000000000000 --- a/packages/components/src/ui/styles/theme/dark-mode-config.js +++ /dev/null @@ -1,7 +0,0 @@ -export const darkModeConfig = { - colorBodyBackground: '#18191A', - colorText: '#E4E6EB', - colorTextMuted: '#7a7a7a', - colorTextInverted: '#050505', - colorTextHeading: '#ffffff', -}; diff --git a/packages/components/src/ui/styles/theme/high-contrast-mode-config.js b/packages/components/src/ui/styles/theme/high-contrast-mode-config.js deleted file mode 100644 index d47dd17009b17..0000000000000 --- a/packages/components/src/ui/styles/theme/high-contrast-mode-config.js +++ /dev/null @@ -1,7 +0,0 @@ -export const highContrastModeConfig = { - colorDivider: '#444', - controlBorderColor: '#444', - controlBorderColorHover: '#444', - controlBorderColorSubtle: '#444', - surfaceBorderColor: '#444', -}; diff --git a/packages/components/src/ui/styles/theme/theme.js b/packages/components/src/ui/styles/theme/theme.js index 9d2e82ad11a00..43afe56f0183a 100644 --- a/packages/components/src/ui/styles/theme/theme.js +++ b/packages/components/src/ui/styles/theme/theme.js @@ -1,4 +1 @@ export { config } from './config'; -export { darkModeConfig } from './dark-mode-config'; -export { highContrastModeConfig } from './high-contrast-mode-config'; -export { darkHighContrastModeConfig } from './dark-high-contrast-mode-config'; From 85943f1e029cd88e37621e90627d51c70da99740 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Mon, 19 Apr 2021 12:27:05 -0700 Subject: [PATCH 16/19] Remove create-theme --- .../src/ui/styles/theme/create-theme.js | 44 ------------------- .../components/src/ui/styles/theme/index.js | 1 - 2 files changed, 45 deletions(-) delete mode 100644 packages/components/src/ui/styles/theme/create-theme.js diff --git a/packages/components/src/ui/styles/theme/create-theme.js b/packages/components/src/ui/styles/theme/create-theme.js deleted file mode 100644 index 5b60d19f0dff2..0000000000000 --- a/packages/components/src/ui/styles/theme/create-theme.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * External dependencies - */ -import colorize from 'tinycolor2'; - -/** - * Internal dependencies - */ -import { get } from '../../create-styles'; -import { space } from '../mixins/space'; -import { config } from './config'; -import { generateColorAdminColors } from './utils'; -import { getComputedColor } from '../../utils/colors'; - -const baseTheme = Object.freeze( Object.assign( {}, config ) ); - -/* eslint-disable jsdoc/valid-types */ -/** - * @param {(props: { get: typeof get, theme: typeof baseTheme, color: typeof colorize, space: typeof space }) => Record} callback - * @return {Record} The theme. - */ -export function createTheme( callback ) { - /* eslint-enable jsdoc/valid-types */ - const props = { - get, - theme: baseTheme, - color: colorize, - space, - }; - - const customConfig = callback( props ); - - let colorAdminColors = {}; - - if ( customConfig.colorAdmin ) { - const colorAdminValue = getComputedColor( customConfig.colorAdmin ); - colorAdminColors = generateColorAdminColors( colorAdminValue ); - } - - return { - ...customConfig, - ...colorAdminColors, - }; -} diff --git a/packages/components/src/ui/styles/theme/index.js b/packages/components/src/ui/styles/theme/index.js index 5bf265f14f643..7b1f54ecf901d 100644 --- a/packages/components/src/ui/styles/theme/index.js +++ b/packages/components/src/ui/styles/theme/index.js @@ -1,2 +1 @@ -export * from './create-theme'; export * from './theme'; From 3ee4a5031c1b247f7e8f6a6401ab7239b1923538 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Mon, 19 Apr 2021 12:58:36 -0700 Subject: [PATCH 17/19] Remove unused theme/utils --- .../components/src/ui/styles/theme/utils.js | 110 ------------------ 1 file changed, 110 deletions(-) delete mode 100644 packages/components/src/ui/styles/theme/utils.js diff --git a/packages/components/src/ui/styles/theme/utils.js b/packages/components/src/ui/styles/theme/utils.js deleted file mode 100644 index f6138eb9b6ba6..0000000000000 --- a/packages/components/src/ui/styles/theme/utils.js +++ /dev/null @@ -1,110 +0,0 @@ -/** - * External dependencies - */ -import colorize from 'tinycolor2'; - -/** - * @param {Record} colors - * @return {Record} Text colors. - */ -export function createTextColors( colors ) { - /** @type {Record} */ - const colorSet = {}; - const entries = Object.entries( colors ); - const light = entries[ 0 ][ 1 ]; - const lighter = colorize( light ).lighten( 15 ).toHexString(); - const dark = entries[ entries.length - 1 ][ 1 ]; - const darker = colorize( dark ).darken( 15 ).toHexString(); - - for ( const [ color, value ] of entries ) { - colorSet[ `${ color }Text` ] = colorize - .mostReadable( value, [ lighter, light, dark, darker ] ) - .toHexString(); - } - - return colorSet; -} - -/** - * - * @param {Record} colors - * @param {boolean} [isDark=false] - * @return {Record} Rgba colors. - */ -export function createRgbaColors( colors, isDark = false ) { - /** @type {Record} */ - const colorSet = {}; - const entries = Object.entries( colors ); - const [ baseColorName, baseColorValue ] = entries[ 2 ]; - const [ colorName ] = baseColorName.split( /\d+/ ); - - const ranges = [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ]; - - const mixBase = isDark ? '#000' : '#fff'; - const readabilityTextBase = isDark ? '#fff' : '#000'; - const adjustMethod = isDark ? 'darken' : 'lighten'; - - ranges.forEach( ( range, index ) => { - let enhancedColorValue = baseColorValue; - - enhancedColorValue = colorize( enhancedColorValue ) - .setAlpha( range / 100 ) - .toRgbString(); - - const testColor = colorize - .mix( baseColorValue, mixBase, index ) - .toRgbString(); - - const isReadable = colorize.isReadable( - testColor, - readabilityTextBase, - {} - ); - - if ( ! isReadable ) { - enhancedColorValue = colorize( enhancedColorValue ) - [ adjustMethod ]( 20 ) - .toRgbString(); - } - - colorSet[ `${ colorName }Rgba${ range }` ] = enhancedColorValue; - } ); - - return colorSet; -} - -/** - * @param {string} key - * @param {import('tinycolor2').ColorInput} color - * @return {Record} Rgb colors. - */ -export function generateRgbColors( key, color ) { - /** @type {Record} */ - const colorSet = { - [ key ]: color, - }; - - const ranges = [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ]; - - ranges.forEach( ( index ) => { - colorSet[ `${ key }Rgba${ index }` ] = colorize( color ) - .setAlpha( index / 100 ) - .toRgbString(); - } ); - - return colorSet; -} - -/** - * @param {import('tinycolor2').ColorInput} color - */ -export function generateColorAdminColors( color ) { - return generateRgbColors( 'colorAdmin', color ); -} - -/** - * @param {import('tinycolor2').ColorInput} color - */ -export function generateColorDestructiveColors( color ) { - return generateRgbColors( 'colorDestructive', color ); -} From e4ac419fa742ef21e1f539833072deeca7d330e9 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Wed, 21 Apr 2021 06:33:30 -0700 Subject: [PATCH 18/19] Remove tokens in favor of just using unstable CSS vars --- packages/components/src/ui/styles/README.md | 11 +++-------- packages/components/src/ui/styles/mixins/space.js | 4 ++-- packages/components/src/ui/styles/theme/config.js | 5 +++++ packages/components/src/ui/styles/tokens.js | 3 --- packages/components/src/ui/styles/ui.js | 2 -- 5 files changed, 10 insertions(+), 15 deletions(-) delete mode 100644 packages/components/src/ui/styles/tokens.js diff --git a/packages/components/src/ui/styles/README.md b/packages/components/src/ui/styles/README.md index 41c09cfe96f2b..5e0ad0cbcc14f 100644 --- a/packages/components/src/ui/styles/README.md +++ b/packages/components/src/ui/styles/README.md @@ -5,8 +5,8 @@ The primary API that `styles` exposes is the `ui` object. It contains the following properties: - `get`: Retrieves a pre-defined set of CSS Custom Properties. See [Theme Configuration](#theme-configuration) below. -- `tokens`: A pre-defined set of theme variables, accessible via the frozen `tokens` object. See [Theme Tokens](#theme-tokens) below. -- Various mixins. See [Mixins](#mixins) below. +- `flow`: Described below. +- `space`: Described below. ## Theme Configuration @@ -15,18 +15,13 @@ Each of the configs declares overrides for the theme variables. The overall list Variables added to the overarching config should align with variables declared in the `base-styles` package. These variables are accessed via the `ui.get` helper exported from `styles` and are exposed as CSS Custom Properties. - -## Theme Tokens - -Tokens are similar to variables except that they are not exposed as CSS Custom Properties. This is to avoid introducing too many new public APIs. Instead, we simply access them off of the `ui.tokens` object as you would any normal JavaScript object. `ui.tokens` is a _frozen_ object so runtime changes are no allowed to it, updates to it must be constant and done in the [`styles/tokens.js`](./tokens.js) module. - ## Mixins Mixins are helper functions for composing and building styles. ### `space` -`space` is the core of the style system's spacing system. It will automatically transform a given space value into the correct spacing for the theme based off the token `gridBase` value. It can accept any number value. +`space` is the core of the style system's spacing system. It will automatically transform a given space value into the correct spacing for the theme based off the `gridBase` variable. It can accept any number value. ### `flow` diff --git a/packages/components/src/ui/styles/mixins/space.js b/packages/components/src/ui/styles/mixins/space.js index ad5765a0203bb..e17900a7e1558 100644 --- a/packages/components/src/ui/styles/mixins/space.js +++ b/packages/components/src/ui/styles/mixins/space.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { tokens } from '../tokens'; +import { get } from '../core'; /** * @param {import('react').ReactText} value @@ -9,6 +9,6 @@ import { tokens } from '../tokens'; */ export function space( value ) { return typeof value === 'number' - ? `calc(${ tokens.gridBase } * ${ value })` + ? `calc(${ get( 'gridBase' ) } * ${ value })` : value; } diff --git a/packages/components/src/ui/styles/theme/config.js b/packages/components/src/ui/styles/theme/config.js index 5cb601e08c9e3..80e41093275d9 100644 --- a/packages/components/src/ui/styles/theme/config.js +++ b/packages/components/src/ui/styles/theme/config.js @@ -72,10 +72,15 @@ const FONT_PROPS = { fontWeightHeading: '600', }; +const SPACING_PROPS = { + gridBase: '4px', +}; + export const config = { ...COLOR_PROPS, // Base ...FONT_PROPS, + ...SPACING_PROPS, // Animations ...ANIMATION_PROPS, }; diff --git a/packages/components/src/ui/styles/tokens.js b/packages/components/src/ui/styles/tokens.js deleted file mode 100644 index 2b25279c1f5a6..0000000000000 --- a/packages/components/src/ui/styles/tokens.js +++ /dev/null @@ -1,3 +0,0 @@ -export const tokens = Object.freeze( { - gridBase: '4px', -} ); diff --git a/packages/components/src/ui/styles/ui.js b/packages/components/src/ui/styles/ui.js index 680e591beee00..9935f0044ee33 100644 --- a/packages/components/src/ui/styles/ui.js +++ b/packages/components/src/ui/styles/ui.js @@ -3,11 +3,9 @@ */ import { get } from './core'; import { space, flow } from './mixins'; -import { tokens } from './tokens'; export const ui = { get, space, flow, - tokens, }; From 3a2056403ecc7c7b690cc6551e1fbac52c4586fa Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Wed, 21 Apr 2021 06:39:32 -0700 Subject: [PATCH 19/19] Clean up some docs --- .../src/ui/styles/components/style-frame-provider.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/ui/styles/components/style-frame-provider.js b/packages/components/src/ui/styles/components/style-frame-provider.js index 2f25a353280ac..27553a026e6bc 100644 --- a/packages/components/src/ui/styles/components/style-frame-provider.js +++ b/packages/components/src/ui/styles/components/style-frame-provider.js @@ -18,7 +18,7 @@ const { cache } = compiler; /** * A special Provider designed specifically for iFrame usage. - * Components using `@wp-g2/styled` that render within will have their + * Components using the style system's styled that render within will have their * styles injected and rendered correctly within the iFrame out-of-the-box. * * No external stylesheet loading is necessary when using . @@ -27,7 +27,7 @@ const { cache } = compiler; * ```jsx * * - * + * * * * ```