From b3c06c2f865d0954eb199cc51c351475694a2504 Mon Sep 17 00:00:00 2001 From: Iampava Date: Fri, 5 Jun 2020 14:56:38 +0300 Subject: [PATCH] custom-properties: extend ThemeProvider to insert CSS Custom Props --- packages/custom-properties/README.md | 108 ++++++++++++++++++++---- packages/custom-properties/package.json | 7 +- packages/custom-properties/src/index.ts | 36 +++++++- packages/custom-properties/test/test.js | 2 +- yarn.lock | 32 ++++++- 5 files changed, 165 insertions(+), 20 deletions(-) diff --git a/packages/custom-properties/README.md b/packages/custom-properties/README.md index 716ed56bd..10ba7ec76 100644 --- a/packages/custom-properties/README.md +++ b/packages/custom-properties/README.md @@ -1,8 +1,7 @@ # @theme-ui/custom-properties -Generate CSS custom properties for use with Theme UI. +Extend [ThemeUI](https://theme-ui.com)'s core functionality with CSS Custom Properties. -https://theme-ui.com ## Installation @@ -10,31 +9,108 @@ https://theme-ui.com yarn add @theme-ui/custom-properties ``` +## API -## Usage +### toCustomProperties -Transform your Theme UI compliant theme config with the library: +Transform your Theme UI compliant theme to an object of CSS Custom Properties. -```js -const toCustomProperties = require('@theme-ui/custom-properties') -const theme = require('../theme'); +**Type**: `Function` -module.exports = () => { - const customProperties = toCustomProperties(theme, '🍭'); +**Parameters**: +1. theme - The theme ui specification object +2. prefix - An optional string prefix for the css custom property (_optional_) - return customProperties; +**Returns**: `Object` +```js +{ + '--color-primary': '#2980b9', + '--color-secondary': '#f7df1e', + '--fontSize-0': 12, + ' -fontSize-1': 14, + '--fontSize-2': 16, + '--fontSize-3': 24, + '--fontSize-4': 32, + '--fontSize-5': 48, + '--fontSize-6': 64 } ``` +**Example**: +```js +import { toCustomProperties } from '@theme-ui/custom-properties'; +import theme from '../theme'; -## Parameters +const customProperties = toCustomProperties(theme, '🍭'); +console.log(customProperties); +``` -The @theme-ui/custom-properties function takes two parameters: +### withCustomProperties +Extend the base `ThemeProvider` to allow native styling by using CSS Custom Properties. -```js -toCustomProperties( $theme, $prefix ); +**Type**: `Function` + +**Parameters**: +1. prefix - An optional string prefix for the css custom property (_optional_) + +**Returns** a React Component which extends the default `ThemeProvider` by adding CSS Custom Properties to the wrapper element. + +For example: + +```jsx +const ExtendedThemeProvider = withCustomProperties('app-name'); + +ReactDOM.render( + +

Hello world!

+
, + root + ); ``` -1. theme - The theme ui specification object -1. prefix - An optional prefix for the css custom property _optional_ +Then in CSS we can do something like: +```css +p { + color: var(--app-name-color-primary); + background: var(--app-name-color-secondary); +} +``` + +These CSS Custom Properties are in total sync with the theme. Also, sub-theming works as expected. + +```jsx +const theme = { + colors: { + primary: 'red', + secondary: 'blue' + } +}; + +const subTheme = { + colors: { + primary: 'orange' + } +}; + +const ExtendedThemeProvider = withCustomProperties('app-name'); + +ReactDOM.render( + +

Hello world!

// red on a blue background + + +

Hello Aliens!

// orange on a blue background +
+ +
, + root +); +``` + +```css +p { + color: var(--app-name-color-primary); + background: var(--app-name-color-secondary); +} +``` \ No newline at end of file diff --git a/packages/custom-properties/package.json b/packages/custom-properties/package.json index 3ba856372..a2edd6274 100644 --- a/packages/custom-properties/package.json +++ b/packages/custom-properties/package.json @@ -1,7 +1,7 @@ { "name": "@theme-ui/custom-properties", "description": "Generate CSS custom properties for use with Theme UI", - "version": "0.4.0-alpha.3", + "version": "0.5.0-alpha.1", "source": "src/index.ts", "main": "dist/index.js", "module": "dist/index.esm.js", @@ -18,8 +18,13 @@ "dependencies": { "pluralize": "^8.0.0" }, + "peerDependencies": { + "react": "^16.11.0", + "theme-ui": "^0.3.1" + }, "devDependencies": { "@theme-ui/css": "^0.4.0-alpha.3", + "@types/theme-ui": "^0.3.2", "@types/pluralize": "^0.0.29" } } diff --git a/packages/custom-properties/src/index.ts b/packages/custom-properties/src/index.ts index 3dffea093..4907dd84f 100644 --- a/packages/custom-properties/src/index.ts +++ b/packages/custom-properties/src/index.ts @@ -1,11 +1,14 @@ +import React, { useEffect, useRef } from 'react' import pluralize from 'pluralize' import { Theme } from '@theme-ui/css' +import { ThemeProvider } from 'theme-ui' +import { ThemeProviderProps, useThemeUI } from '@theme-ui/core' interface CustomProperties { [key: string]: string | number } -export default (theme: Theme, prefix?: string) => { +export function toCustomProperties(theme: Theme, prefix?: string) { const customProperties: CustomProperties = {} const generateProperties = (object: object, previousKey?: string) => { @@ -36,3 +39,34 @@ export default (theme: Theme, prefix?: string) => { return customProperties } + +export function withCustomProperties(prefix?: string) { + return function customThemeProvider(props: ThemeProviderProps) { + const ref = useRef(null) + const outerTheme = useThemeUI().theme + + useEffect(() => { + if (!ref.current) { + return + } + + const theme = typeof props.theme === 'function' + ? props.theme(outerTheme) + : props.theme + const cssProperties = toCustomProperties(theme as Theme, prefix) + + Object.entries(cssProperties).forEach(([key, value]) => { + ref.current!.style.setProperty(key, value.toString()) + }) + }) + + return React.createElement( + 'div', + { + ref, + className: 'theme-ui-provider', + }, + React.createElement(ThemeProvider, props) + ) + } +} diff --git a/packages/custom-properties/test/test.js b/packages/custom-properties/test/test.js index 392a29c51..6d31b99e7 100644 --- a/packages/custom-properties/test/test.js +++ b/packages/custom-properties/test/test.js @@ -1,4 +1,4 @@ -import toCustomProperties from '../src' +import { toCustomProperties } from '../src/index' const theme = { colors: { diff --git a/yarn.lock b/yarn.lock index 38a0eb370..a35e3f5cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3378,6 +3378,13 @@ dependencies: csstype "^2.6.9" +"@types/styled-system__css@*": + version "5.0.11" + resolved "https://registry.yarnpkg.com/@types/styled-system__css/-/styled-system__css-5.0.11.tgz#a9ff7e5d75e69a0d5ccff36acb4bbd491f1a9da9" + integrity sha512-hUieAt4sFS7zwbdU9Vlnn/c3vkfhTMhyiccYGpUSX96nJ4BF3NjLIjMu3cQOYS5EX4gPkHJZhkfdw41ov1NjhQ== + dependencies: + csstype "^2.6.6" + "@types/testing-library__dom@*": version "7.0.2" resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-7.0.2.tgz#2906f8a0dce58b0746c6ab606f786bd06fe6940e" @@ -3401,6 +3408,29 @@ "@types/testing-library__dom" "*" pretty-format "^25.1.0" +"@types/theme-ui@*", "@types/theme-ui@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@types/theme-ui/-/theme-ui-0.3.2.tgz#f8e49734398725f72195866cdc2462a07743bf38" + integrity sha512-xAHYIyIsInPbcRf2YqCnioTmTsVjX+5fClO6NqwNORn0j9deGuSMp2gI8lPjm5b0eZwxM5ugExLbz01lxjjVqw== + dependencies: + "@emotion/serialize" "^0.11.15" + "@types/react" "*" + "@types/styled-system" "*" + "@types/styled-system__css" "*" + "@types/theme-ui__components" "*" + csstype "^2.6.6" + +"@types/theme-ui__components@*": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@types/theme-ui__components/-/theme-ui__components-0.2.5.tgz#65ef4e160e2e0cf7c52ae220f6579a707d33667d" + integrity sha512-qqhIJboXzGXE0ZpKRHrwQvRbuOAcGNyAWMPXXP2jGs65XcaTuDJJpz1Rx5JCaQ1h+Tt99uIriRzZRthWarh1wg== + dependencies: + "@emotion/core" "^10.0.0" + "@emotion/styled" "^10.0.0" + "@types/react" "*" + "@types/styled-system" "*" + "@types/theme-ui" "*" + "@types/tmp@^0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" @@ -7629,7 +7659,7 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" -csstype@^2.2.0, csstype@^2.5.7, csstype@^2.6.10, csstype@^2.6.9: +csstype@^2.2.0, csstype@^2.5.7, csstype@^2.6.10, csstype@^2.6.6, csstype@^2.6.9: version "2.6.10" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==