-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Components: Add create-styles (#30509)
* Components: Add create-styles * Fix disallowed syntaxes * Add missing TS resolution * Remove ThemeProvider and duplicated hooks * Clean up READMEs * Remove unnecessary deps * Remove stray `is` import * Change namespace to experimental to avoid introducing new public APIs * Remove stray mentions of g2 * Remove `css` prop and automatic prop filtering
- Loading branch information
1 parent
c71a997
commit 8aa446b
Showing
39 changed files
with
2,289 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
packages/components/src/ui/create-styles/create-compiler/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# create-compiler | ||
|
||
This module creates the Emotion instance that backs the style system. It integrates plugins and creates the core `css` function that wraps Emotion's `css` function adding support for breakpoint values on each property. | ||
|
||
## Breakpoint values | ||
|
||
Breakpoint values are supported by passing an array of values to a CSS property. For example: | ||
|
||
```js | ||
css({ | ||
width: [300, 500, 700], | ||
}); | ||
``` | ||
|
||
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). | ||
|
||
The individual plugins are documented in [`plugins/README.md`](./plugins/README.md). | ||
|
||
## Custom iframe support | ||
|
||
Emotion by default does not support iframe styling. This style system solves this by implementing a custom `sheet.insert` that exposes a `sheet.insert` event which can be listened to by style providers to receive styles from outside of the current iframe. | ||
|
||
## Interplated Components | ||
|
||
`css` also supports passing style system-connected components as selectors in the same style as `styled-components`. It does this _without any Babel transformations_. Interpolated components are transformed to a special interpolated class name by the `css` function. Components are given an interpolation class name (prefixed by `ic-`) by either the `contextConnect` hook or by `styled` itself. `css` then detects when a component has been passed in and transorms it into a CSS selector. | ||
|
||
For example: | ||
|
||
```js | ||
const Text = styled.div` | ||
color: red; | ||
`; | ||
|
||
const greenText = css` | ||
${Text} { | ||
color: green; | ||
} | ||
`; | ||
``` | ||
|
||
Now any child `Text` of a component that applies the `greenText` generated class name will be targeted with the `color: green` styles. | ||
|
||
Psueudo selectors against the interpolated component are possible as well: | ||
|
||
```js | ||
const blueText = css` | ||
${Text}:first-child { | ||
color: blue; | ||
} | ||
`; | ||
``` |
120 changes: 120 additions & 0 deletions
120
packages/components/src/ui/create-styles/create-compiler/create-compiler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import createEmotion from 'create-emotion'; | ||
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'; | ||
|
||
const defaultOptions = { | ||
key: 'css', | ||
specificityLevel: 1, | ||
rootStore: new RootStore(), | ||
}; | ||
|
||
/* eslint-disable jsdoc/valid-types */ | ||
/** | ||
* @typedef {import('create-emotion').Emotion & { | ||
* breakpoints: typeof breakpoints, | ||
* __events: import('mitt').Emitter, | ||
* generateInterpolationName(): string, | ||
* }} Compiler | ||
*/ | ||
/* eslint-enable jsdoc/valid-types */ | ||
|
||
/** | ||
* @typedef {import('create-emotion').Options & { | ||
* key?: string, | ||
* specificityLevel?: number, | ||
* rootStore: import('../css-custom-properties').RootStore | ||
* }} CreateCompilerOptions | ||
*/ | ||
|
||
/** | ||
* @param {CreateCompilerOptions} options | ||
* @return {Compiler} The compiler. | ||
*/ | ||
export function createCompiler( options ) { | ||
const mergedOptions = { | ||
...defaultOptions, | ||
...options, | ||
}; | ||
|
||
const { key, rootStore, specificityLevel } = mergedOptions; | ||
|
||
const defaultPlugins = createPlugins( { | ||
key, | ||
specificityLevel, | ||
rootStore, | ||
} ); | ||
|
||
if ( options.stylisPlugins ) { | ||
if ( Array.isArray( options.stylisPlugins ) ) { | ||
mergedOptions.stylisPlugins = [ | ||
...defaultPlugins, | ||
...options.stylisPlugins, | ||
]; | ||
} else if ( typeof options.stylisPlugins !== 'undefined' ) { | ||
// just a single plugin was passed in, as is allowed by emotion | ||
mergedOptions.stylisPlugins = [ | ||
...defaultPlugins, | ||
options.stylisPlugins, | ||
]; | ||
} else { | ||
mergedOptions.stylisPlugins = defaultPlugins; | ||
} | ||
} else { | ||
mergedOptions.stylisPlugins = defaultPlugins; | ||
} | ||
|
||
/** | ||
* We're creating a custom Emotion instance to ensure that the style system | ||
* does not conflict with (potential) existing Emotion instances. | ||
* | ||
* We're also able to provide createEmotion with our custom Stylis plugins. | ||
*/ | ||
const customEmotionInstance = { | ||
...createEmotion( mergedOptions ), | ||
/** | ||
* Exposing the breakpoints used in the internal Style system. | ||
*/ | ||
breakpoints, | ||
/** | ||
* An internal custom event emitter (pub/sub) for Emotion. | ||
* This is currently used in <StyleFrameProvider /> | ||
* to subscribe to and sync style injection. | ||
*/ | ||
__events: mitt(), | ||
generateInterpolationName, | ||
}; | ||
|
||
/** | ||
* Enhance the base css function from Emotion to add features like responsive | ||
* value handling and compiling an Array of css() calls. | ||
*/ | ||
const { css } = customEmotionInstance; | ||
customEmotionInstance.css = createCSS( css ); | ||
|
||
/** | ||
* Modify the sheet.insert method to emit a `sheet.insert` event | ||
* within the internal custom event emitter. | ||
*/ | ||
const __insert = customEmotionInstance.sheet.insert; | ||
customEmotionInstance.sheet.insert = ( | ||
/* eslint-disable jsdoc/valid-types */ | ||
/** @type {[rule: string]} */ ...args | ||
) => | ||
/* eslint-enable jsdoc/valid-types */ | ||
{ | ||
__insert.apply( customEmotionInstance.sheet, [ ...args ] ); | ||
customEmotionInstance.__events.emit( 'sheet.insert', ...args ); | ||
}; | ||
|
||
return customEmotionInstance; | ||
} |
65 changes: 65 additions & 0 deletions
65
packages/components/src/ui/create-styles/create-compiler/create-css.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { isPlainObject } from 'lodash'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { responsive } from './responsive'; | ||
|
||
/** | ||
* @param {CSS} compile | ||
* @return {CSS} The CSS function | ||
*/ | ||
export function createCSS( compile ) { | ||
/** | ||
* An enhanced version of the compiler's (Emotion) CSS function. | ||
* This enhanced CSS supports dynamic responsive (breakpoint-based) styles if | ||
* the value is an array of values. | ||
* | ||
* @example | ||
* ```js | ||
* // The following will render a CSS rule where the widths will be: | ||
* // 100px for mobile | ||
* // 200px for tablet | ||
* // 500px for desktop | ||
* css({ | ||
* width: [100, 200, 500] | ||
* }) | ||
* ``` | ||
* @param {Parameters<CSS>} args | ||
* @return {ReturnType<CSS>} The compiled CSS className associated with the styles. | ||
*/ | ||
function css( ...args ) { | ||
const [ arg, ...rest ] = args; | ||
|
||
if ( isPlainObject( arg ) ) { | ||
return compile( | ||
responsive( /** @type {ObjectInterpolation} */ ( arg ) ) | ||
); | ||
} | ||
|
||
if ( Array.isArray( arg ) ) { | ||
for ( let i = 0, len = arg.length; i < len; i++ ) { | ||
const n = arg[ i ]; | ||
if ( isPlainObject( n ) ) { | ||
arg[ i ] = responsive( | ||
/** @type {ObjectInterpolation} */ ( n ) | ||
); | ||
} | ||
} | ||
return compile( ...[ arg, ...rest ] ); | ||
} | ||
|
||
return compile( ...args ); | ||
} | ||
|
||
// @ts-ignore No amount of zhuzhing will convince TypeScript that a function with the parameters and return type for CSS is in fact the same type | ||
return css; | ||
} | ||
|
||
/* eslint-disable jsdoc/valid-types */ | ||
/** @typedef {import('create-emotion').Emotion['css']} CSS */ | ||
/** @typedef {import('create-emotion').ObjectInterpolation<unknown>} ObjectInterpolation */ | ||
/* eslint-enable jsdoc/valid-types */ |
3 changes: 3 additions & 0 deletions
3
packages/components/src/ui/create-styles/create-compiler/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './create-compiler'; | ||
export * from './create-css'; | ||
export * from './responsive'; |
33 changes: 33 additions & 0 deletions
33
packages/components/src/ui/create-styles/create-compiler/plugins/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# plugins | ||
|
||
This foler contains all the applied plugins in the style system. | ||
|
||
**Nota bene**: All of the plugins can be removed once IE11 support is officially dropped. | ||
|
||
## Extra Specificity | ||
|
||
This plugin automatically compounds selector specificity by simply repeating the selector x number of times. For example, if a specificity of 3 is passed in, the plugin will transform: | ||
|
||
```css | ||
.css-abc123 { | ||
color: red; | ||
} | ||
``` | ||
|
||
into: | ||
|
||
```css | ||
.css-abc123.css-abc123.css-abc123 { | ||
color: red; | ||
} | ||
``` | ||
|
||
This is meant to prevent "hacks" from being applied to the component system via regular css selection (or rather to make it difficult/annoying to do so), forcing consumers to use the style system itself, for example, the `css` prop and theme variables, to apply custom styles. | ||
|
||
It is currently set to a specificity of 1 to disable it. This may be reversed in the future. If it isn't reversed in the future, at some point we shoiuld just remove it. | ||
|
||
## CSS Variable Fallback | ||
|
||
The [`css-variables.js` ](./css-variables.js) plugin automatically generates fallback variables to support browsers that lack CSS variable support. | ||
|
||
Given WordPress core is dropping IE11 support,we might be able to drop this plugin altogether. |
Oops, something went wrong.