diff --git a/packages/custom-properties/.npmignore b/packages/custom-properties/.npmignore new file mode 100644 index 000000000..37ccaba94 --- /dev/null +++ b/packages/custom-properties/.npmignore @@ -0,0 +1,3 @@ +babel.config.js +test +coverage diff --git a/packages/custom-properties/README.md b/packages/custom-properties/README.md new file mode 100644 index 000000000..df4b79535 --- /dev/null +++ b/packages/custom-properties/README.md @@ -0,0 +1,39 @@ +# @theme-ui/custom-properties + +Generate CSS custom properties for use with Theme UI. + + +## Installation + +``` +yarn add @theme-ui/custom-properties +``` + + +## Usage + +Transform your Theme UI compliant theme config with the library: + +```js +const toCustomProperties = require('@theme-ui/custom-properties') +const theme = require('../theme'); + +module.exports = () => { + const customProperties = toCustomProperties(theme, '🍭'); + + return customProperties; +} +``` + + +## Parameters + +The @theme-ui/custom-properties function takes two parameters: + +```js +toCustomProperties( $theme, $prefix ); +``` + +1. theme - The theme ui specification object +1. prefix - An optional prefix for the css custom property _optional_ + diff --git a/packages/custom-properties/babel.config.js b/packages/custom-properties/babel.config.js new file mode 100644 index 000000000..46bf5309f --- /dev/null +++ b/packages/custom-properties/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config') diff --git a/packages/custom-properties/package.json b/packages/custom-properties/package.json new file mode 100644 index 000000000..00359e23a --- /dev/null +++ b/packages/custom-properties/package.json @@ -0,0 +1,20 @@ +{ + "name": "@theme-ui/custom-properties", + "description": "Generate CSS custom properties for use with Theme UI", + "version": "0.0.0", + "main": "dist/index.js", + "module": "dist/index.esm.js", + "author": "Alex Page ", + "license": "MIT", + "scripts": { + "prepare": "microbundle --no-compress", + "watch": "microbundle watch --no-compress" + }, + "devDependencies": {}, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "pluralize": "^8.0.0" + } +} diff --git a/packages/custom-properties/src/index.js b/packages/custom-properties/src/index.js new file mode 100644 index 000000000..3f47710e2 --- /dev/null +++ b/packages/custom-properties/src/index.js @@ -0,0 +1,33 @@ +import pluralize from 'pluralize' + +export default (theme, prefix) => { + const customProperties = {} + + const generateProperties = (object, previousKey) => { + Object.entries(object).forEach(([key, value]) => { + let formattedKey = pluralize(key, 1) + + if (prefix && !previousKey) { + formattedKey = `${prefix}-${formattedKey}` + } + + const newKey = previousKey + ? previousKey + '-' + formattedKey + : formattedKey + + if (Array.isArray(value)) { + value.forEach((item, i) => { + customProperties[`--${newKey}-${i}`] = item + }) + } else if (Object(value) === value) { + generateProperties(value, newKey) + } else { + customProperties[`--${newKey}`] = value + } + }) + } + + generateProperties(theme) + + return customProperties +} diff --git a/packages/custom-properties/test/__snapshots__/test.js.snap b/packages/custom-properties/test/__snapshots__/test.js.snap new file mode 100644 index 000000000..0c924f485 --- /dev/null +++ b/packages/custom-properties/test/__snapshots__/test.js.snap @@ -0,0 +1,63 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`transforms a theme config to CSS custom properties 1`] = ` +Object { + "--color-accent": "#609", + "--color-background": "#fff", + "--color-dark-background-surface": "#fff", + "--color-dark-foreground-text": "#000", + "--color-muted": "#f6f6f6", + "--color-primary": "#07c", + "--color-secondary": "#05a", + "--color-text": "#000", + "--font-body": "system-ui, sans-serif", + "--font-heading": "system-ui, sans-serif", + "--font-monospace": "Menlo, monospace", + "--fontWeight-body": 400, + "--fontWeight-bold": 700, + "--fontWeight-heading": 700, + "--lineHeight-0": 1.5, + "--lineHeight-1": 1.125, + "--size-0": "10em", + "--size-1": "20em", + "--size-2": "30em", + "--size-3": "40em", + "--space-0": 0, + "--space-1": 2, + "--space-2": 3, + "--space-3": 4, + "--space-4": 5, + "--space-5": 6, +} +`; + +exports[`transforms a theme config to CSS custom properties with prefix 1`] = ` +Object { + "--🍭-color-accent": "#609", + "--🍭-color-background": "#fff", + "--🍭-color-dark-background-surface": "#fff", + "--🍭-color-dark-foreground-text": "#000", + "--🍭-color-muted": "#f6f6f6", + "--🍭-color-primary": "#07c", + "--🍭-color-secondary": "#05a", + "--🍭-color-text": "#000", + "--🍭-font-body": "system-ui, sans-serif", + "--🍭-font-heading": "system-ui, sans-serif", + "--🍭-font-monospace": "Menlo, monospace", + "--🍭-fontWeight-body": 400, + "--🍭-fontWeight-bold": 700, + "--🍭-fontWeight-heading": 700, + "--🍭-lineHeight-0": 1.5, + "--🍭-lineHeight-1": 1.125, + "--🍭-size-0": "10em", + "--🍭-size-1": "20em", + "--🍭-size-2": "30em", + "--🍭-size-3": "40em", + "--🍭-space-0": 0, + "--🍭-space-1": 2, + "--🍭-space-2": 3, + "--🍭-space-3": 4, + "--🍭-space-4": 5, + "--🍭-space-5": 6, +} +`; diff --git a/packages/custom-properties/test/test.js b/packages/custom-properties/test/test.js new file mode 100644 index 000000000..aa90c46ec --- /dev/null +++ b/packages/custom-properties/test/test.js @@ -0,0 +1,45 @@ +import toCustomProperties from '../src' + +const theme = { + colors: { + text: '#000', + background: '#fff', + primary: '#07c', + secondary: '#05a', + accent: '#609', + muted: '#f6f6f6', + dark: { + foreground: { + text: '#000', + }, + background: { + surface: '#fff', + }, + }, + }, + fonts: { + body: 'system-ui, sans-serif', + heading: 'system-ui, sans-serif', + monospace: 'Menlo, monospace', + }, + fontWeights: { + body: 400, + heading: 700, + bold: 700, + }, + lineHeights: [1.5, 1.125], + space: [0, 2, 3, 4, 5, 6], + size: ['10em', '20em', '30em', '40em'], +} + +it('transforms a theme config to CSS custom properties', () => { + const result = toCustomProperties(theme) + + expect(result).toMatchSnapshot() +}) + +it('transforms a theme config to CSS custom properties with prefix', () => { + const result = toCustomProperties(theme, '🍭') + + expect(result).toMatchSnapshot() +}) diff --git a/yarn.lock b/yarn.lock index aad722802..62267efbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15988,6 +15988,11 @@ please-upgrade-node@^3.1.1: dependencies: semver-compare "^1.0.0" +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + pn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"