diff --git a/docs/manifest.json b/docs/manifest.json index 8c0881895f142..43b98b1c79878 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1817,6 +1817,12 @@ "markdown_source": "../packages/token-list/README.md", "parent": "packages" }, + { + "title": "@wordpress/ui-utils", + "slug": "packages-ui-utils", + "markdown_source": "../packages/ui-utils/README.md", + "parent": "packages" + }, { "title": "@wordpress/url", "slug": "packages-url", diff --git a/packages/compose/CHANGELOG.md b/packages/compose/CHANGELOG.md index d0ad061a871a4..80ab0d2f1b4b8 100644 --- a/packages/compose/CHANGELOG.md +++ b/packages/compose/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### New Features + +- Add `is` utility + ## 3.4.0 (2019-06-12) ### New Features diff --git a/packages/ui-utils/.npmrc b/packages/ui-utils/.npmrc new file mode 100644 index 0000000000000..9cf9495031ecc --- /dev/null +++ b/packages/ui-utils/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/packages/ui-utils/CHANGELOG.md b/packages/ui-utils/CHANGELOG.md new file mode 100644 index 0000000000000..f11e8cd301086 --- /dev/null +++ b/packages/ui-utils/CHANGELOG.md @@ -0,0 +1,5 @@ + + +## Unreleased + +Initial release. diff --git a/packages/ui-utils/README.md b/packages/ui-utils/README.md new file mode 100644 index 0000000000000..a3e4825caeb56 --- /dev/null +++ b/packages/ui-utils/README.md @@ -0,0 +1,68 @@ +# UI Utils + +A collection of utilities useful for building user interfaces. + +## API + + + +# **isDefined** + +Checks whether a value is defined, asserting that it is neither +null nor undefined. + +_Parameters_ + +- _value_ `(T|undefined|null)`: The value to check. + +_Returns_ + +- (unknown type): Whether the value is undefined. + +# **isObjectInterpolation** + +There's no way to detect whether an `any` type is an `ObjectInterpolation` because `ObjectInterpolation`s +are merely objects where the keys are either (1) [CSS property names](https://github.com/emotion-js/emotion/blob/a72e6dc0f326b7d3d6067698d433018ee8c4cbf1/packages/serialize/types/index.d.ts#L10), +(2) [CSS Pseudo property names](https://github.com/emotion-js/emotion/blob/a72e6dc0f326b7d3d6067698d433018ee8c4cbf1/packages/serialize/types/index.d.ts#L18), +or (3) [anything else where the value for the key is another interpolation](https://github.com/emotion-js/emotion/blob/a72e6dc0f326b7d3d6067698d433018ee8c4cbf1/packages/serialize/types/index.d.ts#L19). +That means ObjectInterpolations can look all of the following ways: + +```js +const oi = { + color: 'black', +}; + +const oi = { + ':disabled': css`color: black;`, +}; + +const oi = { + '@media (prefers-color-scheme: light)': css({ + backgroundColor: 'black', + color: 'white', + }), +}; +``` + +Therefore, this function only accepts `TemplateStringsArray` and `Interpolation` for it's arguments rather than `any`, which +cannot be refined to an `ObjectInterpolation`. However, given any generic `Interpolation`, we _can_ tell whether it is an +`ObjectInterpolation` specifically by simply checking whether the value is "plain object" as defined by `lodash`'s `isPlainObject`. + +Note: The links above reference a specific commit for **Emotion 10**. Emotion 11 is out but we're stuck on Emotion 10 until we can +re-write `create-styles` and upgrade all of `@wordpress/components` to use the new version of Emotion. + +At that point we'll have to revisit this function anyway as it seems that the `ObjectInterpolation` type no longer +exists and that the concept has evolved. + +_Parameters_ + +- _value_ (unknown type): The value to check. + +_Returns_ + +- (unknown type): Whether the value is an ObjectInterpolation. + + + + +

Code is Poetry.

diff --git a/packages/ui-utils/package.json b/packages/ui-utils/package.json new file mode 100644 index 0000000000000..22e5dd6d174f6 --- /dev/null +++ b/packages/ui-utils/package.json @@ -0,0 +1,39 @@ +{ + "name": "@wordpress/ui-utils", + "version": "0.0.1", + "description": "A collection of simple utilities for building user interfaces.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ + "wordpress", + "gutenberg", + "utils" + ], + "homepage": "https://github.com/WordPress/gutenberg/tree/master/packages/ui-utils/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git", + "directory": "packages/ui-utils" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "files": [ + "build", + "build-module", + "build-types", + "src", + "*.md" + ], + "main": "build/index.js", + "module": "build-module/index.js", + "react-native": "src/index", + "types": "build-types", + "sideEffects": false, + "dependencies": { + "lodash": "^4.17.19" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/ui-utils/src/index.js b/packages/ui-utils/src/index.js new file mode 100644 index 0000000000000..6d411d711a52e --- /dev/null +++ b/packages/ui-utils/src/index.js @@ -0,0 +1,2 @@ +export { default as isDefined } from './is-defined'; +export { default as isObjectInterpolation } from './is-object-interpolation'; diff --git a/packages/ui-utils/src/is-defined/index.js b/packages/ui-utils/src/is-defined/index.js new file mode 100644 index 0000000000000..8e9c0b43b408b --- /dev/null +++ b/packages/ui-utils/src/is-defined/index.js @@ -0,0 +1,13 @@ +/* eslint-disable jsdoc/valid-types */ +/** + * Checks whether a value is defined, asserting that it is neither + * null nor undefined. + * + * @template T + * @param {T | undefined | null} value The value to check. + * @return {value is T} Whether the value is undefined. + */ +const isDefined = ( value ) => value !== null && value !== undefined; + +export default isDefined; +/* eslint-enable jsdoc/valid-types */ diff --git a/packages/ui-utils/src/is-object-interpolation/index.js b/packages/ui-utils/src/is-object-interpolation/index.js new file mode 100644 index 0000000000000..469e84daf0ee8 --- /dev/null +++ b/packages/ui-utils/src/is-object-interpolation/index.js @@ -0,0 +1,49 @@ +/* global TemplateStringsArray */ +/** + * External dependencies + */ +import isPlainObject from 'lodash/isPlainObject'; + +/* eslint-disable jsdoc/valid-types */ +/** + * + * There's no way to detect whether an `any` type is an `ObjectInterpolation` because `ObjectInterpolation`s + * are merely objects where the keys are either (1) [CSS property names](https://github.com/emotion-js/emotion/blob/a72e6dc0f326b7d3d6067698d433018ee8c4cbf1/packages/serialize/types/index.d.ts#L10), + * (2) [CSS Pseudo property names](https://github.com/emotion-js/emotion/blob/a72e6dc0f326b7d3d6067698d433018ee8c4cbf1/packages/serialize/types/index.d.ts#L18), + * or (3) [anything else where the value for the key is another interpolation](https://github.com/emotion-js/emotion/blob/a72e6dc0f326b7d3d6067698d433018ee8c4cbf1/packages/serialize/types/index.d.ts#L19). + * That means ObjectInterpolations can look all of the following ways: + * + * ```js + * const oi = { + * color: 'black', + * }; + * + * const oi = { + * ':disabled': css`color: black;`, + * }; + * + * const oi = { + * '@media (prefers-color-scheme: light)': css({ + * backgroundColor: 'black', + * color: 'white', + * }), + * }; + * ``` + * + * Therefore, this function only accepts `TemplateStringsArray` and `Interpolation` for it's arguments rather than `any`, which + * cannot be refined to an `ObjectInterpolation`. However, given any generic `Interpolation`, we _can_ tell whether it is an + * `ObjectInterpolation` specifically by simply checking whether the value is "plain object" as defined by `lodash`'s `isPlainObject`. + * + * Note: The links above reference a specific commit for **Emotion 10**. Emotion 11 is out but we're stuck on Emotion 10 until we can + * re-write `create-styles` and upgrade all of `@wordpress/components` to use the new version of Emotion. + * + * At that point we'll have to revisit this function anyway as it seems that the `ObjectInterpolation` type no longer + * exists and that the concept has evolved. + * + * @param {TemplateStringsArray | import('create-emotion').Interpolation} value The value to check. + * @return {value is import('create-emotion').ObjectInterpolation} Whether the value is an ObjectInterpolation. + */ +const isObjectInterpolation = ( value ) => isPlainObject( value ); +/* eslint-enable jsdoc/valid-types */ + +export default isObjectInterpolation;