diff --git a/packages/custom-properties/README.md b/packages/custom-properties/README.md
index 716ed56bd..10b5182a7 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,118 @@ 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
+// Example response
+{
+ '--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_)
+2. className - An optional class name to add onto the wrapper. All CSS Custom Properties will be defined on this element.
+
+**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', 'extended-theme-provider');
+
+ReactDOM.render(
+
+ Hello world!
+ ,
+ root
+ );
```
-1. theme - The theme ui specification object
-1. prefix - An optional prefix for the css custom property _optional_
+will render:
+
+```jsx
+
+```
+
+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 c2fe95f08..89214f0eb 100644
--- a/packages/custom-properties/package.json
+++ b/packages/custom-properties/package.json
@@ -17,7 +17,11 @@
"access": "public"
},
"dependencies": {
- "pluralize": "^8.0.0"
+ "pluralize": "^8.0.0",
+ "@theme-ui/core": "^0.4.0-alpha.3"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0"
},
"devDependencies": {
"@theme-ui/css": "0.6.0-alpha.1",
diff --git a/packages/custom-properties/src/index.ts b/packages/custom-properties/src/index.ts
index 3dffea093..b95a82e7b 100644
--- a/packages/custom-properties/src/index.ts
+++ b/packages/custom-properties/src/index.ts
@@ -1,11 +1,13 @@
+import React, { useEffect, useRef } from 'react'
import pluralize from 'pluralize'
import { Theme } from '@theme-ui/css'
+import { ThemeProviderProps, useThemeUI, ThemeProvider } from '@theme-ui/core'
interface CustomProperties {
[key: string]: string | number
}
-export default (theme: Theme, prefix?: string) => {
+export default function toCustomProperties(theme: Theme, prefix?: string) {
const customProperties: CustomProperties = {}
const generateProperties = (object: object, previousKey?: string) => {
@@ -36,3 +38,37 @@ export default (theme: Theme, prefix?: string) => {
return customProperties
}
+
+export function withCustomProperties(
+ prefix?: string,
+ className: string = 'theme-ui-provider'
+) {
+ 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, prefix)
+
+ Object.entries(cssProperties).forEach(([key, value]) => {
+ ref.current!.style.setProperty(key, value.toString())
+ })
+ })
+
+ return React.createElement(
+ 'div',
+ {
+ ref,
+ className,
+ },
+ React.createElement(ThemeProvider, props)
+ )
+ }
+}
diff --git a/packages/custom-properties/test/__snapshots__/test.js.snap b/packages/custom-properties/test/__snapshots__/test.js.snap
index 1cac57cf8..a93295943 100644
--- a/packages/custom-properties/test/__snapshots__/test.js.snap
+++ b/packages/custom-properties/test/__snapshots__/test.js.snap
@@ -1,5 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`adds a specific className on the wrapping element of ThemeProvider 1`] = `
+
+`;
+
+exports[`adds the default className on the wrapping element of ThemeProvider 1`] = `
+
+`;
+
exports[`transforms a theme config to CSS custom properties 1`] = `
Object {
"--color-accent": "#609",
diff --git a/packages/custom-properties/test/test.js b/packages/custom-properties/test/test.js
index 392a29c51..c2415cd23 100644
--- a/packages/custom-properties/test/test.js
+++ b/packages/custom-properties/test/test.js
@@ -1,4 +1,6 @@
-import toCustomProperties from '../src'
+import React from 'react'
+import renderer from 'react-test-renderer'
+import toCustomProperties, { withCustomProperties } from '../src'
const theme = {
colors: {
@@ -45,3 +47,27 @@ it('transforms a theme config to CSS custom properties with prefix', () => {
expect(result).toMatchSnapshot()
})
+
+it('adds the default className on the wrapping element of ThemeProvider', () => {
+ const ExtendedThemeProvider = withCustomProperties('🍭')
+ const themeProvider = renderer.create(
+
+ Hello world!
+
+ )
+
+ let tree = themeProvider.toJSON()
+ expect(tree).toMatchSnapshot()
+})
+
+it('adds a specific className on the wrapping element of ThemeProvider', () => {
+ const ExtendedThemeProvider = withCustomProperties('🍭', '🍧')
+ const themeProvider = renderer.create(
+
+ Hello world!
+
+ )
+
+ let tree = themeProvider.toJSON()
+ expect(tree).toMatchSnapshot()
+})