diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..ea19f450 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,116 @@ +M5Stack Documents logo + +[![npm version](https://img.shields.io/npm/v/style-dictionary.svg?style=flat-square)](https://badge.fury.io/js/style-dictionary) +![license](https://img.shields.io/npm/l/style-dictionary.svg?style=flat-square) +[![Build Status](https://img.shields.io/travis/amzn/style-dictionary.svg?style=flat-square)](https://travis-ci.org/amzn/style-dictionary) +[![code climate](https://img.shields.io/codeclimate/github/amzn/style-dictionary.svg?style=flat-square)](https://codeclimate.com/github/amzn/style-dictionary) + +# M5Stack Documents +> *Style once, use everywhere.* + +A M5Stack Documentation is a system that allows you to define styles once, in a way for any platform or language to consume. A single place to create and edit your styles, and a single command exports these rules to all the places you need them - iOS, Android, CSS, JS, HTML, sketch files, style documentation, etc. It is available as a CLI through npm, but can also be used like any normal node module if you want to extend its functionality. + +When you are managing user experiences, it can be quite challenging to keep styles consistent and synchronized across multiple development platforms and devices. At the same time, designers, developers, PMs and others must be able to have consistent and up-to-date style documentation to enable effective work and communication. Even then, mistakes inevitably happen and the design may not be implemented accurately. StyleDictionary solves this by automatically generating style definitions across all platforms from a single source - removing roadblocks, errors, and inefficiencies across your workflow. + +## Watch the Demo on Youtube +[![Watch the video](assets/fake_player.png)](http://youtu.be/1HREvonfqhY) + +## The basics +__A M5Stack Documents consists of:__ +1. [Style properties](#style-properties) organized in JSON files +1. Static assets that can be used across platforms + +__What a M5Stack Documents does:__ +1. Allows the style properties and assets to be consumed in any platform or language + +Let's take a look at a very basic example. + +```json +{ + "size": { + "font": { + "small" : { "value": "10px" }, + "medium": { "value": "16px" }, + "large" : { "value": "24px" }, + "base" : { "value": "{size.font.medium.value}" } + } + } +} +``` + +Here we are creating some basic font size properties. The style property `size.font.small` is "10px" for example. The style definition size.font.base.value is automatically aliased to the value found in size.font.medium.value, so both of those resolve to "16px". + +Now what the M5Stack Documents build system will do with this information is convert it to different formats so that you can use these values in any type of codebase. From this one file you can generate any number of files like: + +```scss +$size-font-small: 10px; +$size-font-medium: 16px; +$size-font-large: 24px; +$size-font-base: 16px; +``` + +```xml +10sp +16sp +24sp +16sp +``` + +```objectivec +float const SizeFontSmall = 10.00f; +float const SizeFontMedium = 16.00f; +float const SizeFontLarge = 24.00f; +float const SizeFontBase = 16.00f; +``` + +This is a very simple example, take a deeper dive into the M5Stack Documents framework in + +The M5Stack Documents framework is completely extensible and modular so you can create any type of file from a M5Stack Documents. +If there is a new language, platform, file type, you can extend the M5Stack Documents framework to create the files you need. + +__Some other things you can build with a M5Stack Documents__ +1. Images and graphics +1. Sketch files +1. Documentation site +1. _Literally anything_ + + +## Style Properties + +> Synonyms: design token, design variable, design constant, atom + +A style property is a key/value data to describe any fundamental/atomic visual properties. This information is stored in a canonical +source, the M5Stack Documents, and transformed for use in different platforms, languages, and contexts. A simple example is a color. +A color can be represented in many ways, all of these are the same color: `#ffffff`, `rgb(255,255,255)`, `hsl(0,0,1)`. + +A M5Stack Documents organizes style properties in a structured way for easy access. Style properties are organized as a deep object +with the leaf nodes being the style properties. + +```json +{ + "color": { + "font": { + "base": { "value": "#111111" }, + "secondary": { "value": "#333333" }, + "tertiary": { "value": "#666666" }, + "inverse": { + "base": { "value": "#ffffff" } + } + } + } +} +``` + +In this example there are 4 style properties: `color.font.base`, `color.font.secondary`, `color.font.tertiary`, and `color.font.inverse.base`. +A style property is any object in the JSON that has a `value` attribute on it. In this way you can nest properties at different levels. +This allows you to easily access the property as well as do things like get all the inverse font colors. + + +## Contributing + +Please help make this framework better. For more information take a look at [CONTRIBUTING.md](https://github.com/amzn/style-dictionary/blob/master/CONTRIBUTING.md) + + +## License + +[Apache 2.0](https://github.com/amzn/style-dictionary/blob/master/LICENSE) diff --git a/docs/_coverpage.md b/docs/_coverpage.md new file mode 100644 index 00000000..de5495c6 --- /dev/null +++ b/docs/_coverpage.md @@ -0,0 +1,12 @@ +![logo](assets/logo.png) + +# Style Dictionary + +> Style once, use everywhere. + +**Style Dictionary** is a build system that allows you to define styles once, in a way for any platform or language to consume. A single place to create and edit your styles, and a single command exports these rules to all the places you need them - iOS, Android, CSS, JS, HTML, sketch files, style documentation, or anything you can think of. It is available as a CLI through npm, but can also be used like any normal node module if you want to extend its functionality. + +[GitHub](https://github.com/amzn/style-dictionary) +[Get Started](README.md) + +![color](#D9F8F5) diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 00000000..bd3b90bb --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,21 @@ +- Getting started + - [Overview](README.md) + - [Quick Start](quick_start.md) + - [Examples](examples.md) + - [Package structure](package_structure.md) + - [Extending](extending.md) + +- Reference + - [API](api.md) + - [Transforms](transforms.md) + - [Transform groups](transform_groups.md) + - [Formats](formats.md) + - [Templates](templates.md) + - [Actions](actions.md) + - [Build process](build_process.md) + +- **Links** +- [![Code](https://icongr.am/feather/code.svg?size=16&color=808080)Demo Sandbox](https://codesandbox.io/s/xv36w4695o) +- [![Github](https://icongram.jgog.in/simple/github.svg?color=808080&size=16)Github](https://github.com/jhildenbiddle/docsify-themeable) +- [![NPM](https://icongram.jgog.in/simple/npm.svg?colored&size=16)NPM](https://www.npmjs.com/package/docsify-themeable) +- [![Twitter](https://icongram.jgog.in/simple/twitter.svg?colored&size=16)@jhildenbiddle](http://twitter.com/jhildenbiddle) \ No newline at end of file diff --git a/docs/actions.md b/docs/actions.md new file mode 100644 index 00000000..1fe90a01 --- /dev/null +++ b/docs/actions.md @@ -0,0 +1,44 @@ +# Actions + +Actions provide a way to run custom build code such as generating binary assets like images. + +Here are all the actions that come with the Style Dictionary build system. We try to include what most people might need. You can define custom actions with the [`registerAction`](api.md#registeraction). If you think we are missing some things, take a look at our [contributing docs](https://github.com/amzn/style-dictionary/blob/master/CONTRIBUTING.md) and send us a pull request! If you have a specific need for your project, you can always write your own [custom actions](#adding-custom-actions). + +You use actions in your config file under platforms > [platform] > actions + +```json +{ + "source": ["properties/**/*.json"], + "platforms": { + "android": { + "transformGroup": "android", + "files": [], + "actions": ["copy_assets"] + } + } +} +``` + + +---- + +## Pre-defined Actions + +[lib/common/actions.js](https://github.com/amzn/style-dictionary/blob/master/lib/common/actions.js) + +### android/copyImages + + +Action to copy images into appropriate android directories. + + +* * * + +### copy_assets + + +Action that copies everything in the assets directory to a new assets directory in the build path of the platform. + + +* * * + diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 00000000..2a3e4652 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,296 @@ +# API + +### buildAllPlatforms +> StyleDictionary.buildAllPlatforms() ⇒ [style-dictionary](#module_style-dictionary) + + + + +The only top-level method that needs to be called +to build the Style Dictionary. + +**Example** +```js +const StyleDictionary = require('style-dictionary').extend('config.json'); +StyleDictionary.buildAllPlatforms(); +``` + +* * * + +### buildPlatform +> StyleDictionary.buildPlatform(platform) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Takes a platform and performs all transforms to +the properties object (non-mutative) then +builds all the files and performs any actions. This is useful if you only want to +build the artifacts of one platform to speed up the build process. + +This method is also used internally in [buildAllPlatforms](#buildAllPlatforms) to +build each platform defined in the config. + + +| Param | Type | Description | +| --- | --- | --- | +| platform | String | Name of the platform you want to build. | + +**Example** +```js +StyleDictionary.buildPlatform('web'); +``` +```bash +$ style-dictionary build --platform web +``` + +* * * + +### cleanAllPlatforms +> StyleDictionary.cleanAllPlatforms() ⇒ [style-dictionary](#module_style-dictionary) + + + + +Does the reverse of [buildAllPlatforms](#buildAllPlatforms) by +performing a clean on each platform. This removes all the files +defined in the platform and calls the undo method on any actions. + + +* * * + +### cleanPlatform +> StyleDictionary.cleanPlatform(platform) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Takes a platform and performs all transforms to +the properties object (non-mutative) then +cleans all the files and perfoms the undo method of any [actions](actions.md). + + +| Param | Type | +| --- | --- | +| platform | String | + + +* * * + +### exportPlatform +> StyleDictionary.exportPlatform(platform) ⇒ Object + + + + +Exports a properties object with applied +platform transforms. + +This is useful if you want to use a style +dictionary in JS build tools like webpack. + + +| Param | Type | Description | +| --- | --- | --- | +| platform | String | The platform to be exported. Must be defined on the style dictionary. | + + +* * * + +### extend +> StyleDictionary.extend(config) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Create a Style Dictionary + + +| Param | Type | Description | +| --- | --- | --- | +| config | [Config](#Config) | Configuration options to build your style dictionary. If you pass a string, it will be used as a path to a JSON config file. You can also pass an object with the configuration. | + +**Example** +```js +const StyleDictionary = require('style-dictionary').extend('config.json'); + +const StyleDictionary = require('style-dictionary').extend({ + source: ['properties/*.json'], + platforms: { + scss: { + transformGroup: 'scss', + buildPath: 'build/', + files: [{ + destination: 'variables.scss', + format: 'scss/variables' + }] + } + // ... + } +}); +``` + +* * * + +### registerAction +> StyleDictionary.registerAction(action) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Adds a custom action to the style property builder. Custom +actions can do whatever you need, such as: copying files, +base64'ing files, running other build scripts, etc. +After you register a custom action, you then use that +action in a platform your config.json + +Actions run after the files in a platform are generated so you +can perform operations on files generated by the style dictionary. +Actions are run sequentially, if you write synchronous code then +it will block other actions, or if you use asynchronous code like Promises +it will not block. + + +| Param | Type | Description | +| --- | --- | --- | +| action | Object | | +| action.name | String | The name of the action | +| action.do | function | The action in the form of a function. | +| [action.undo] | function | A function that undoes the action. | + +**Example** +```js +StyleDictionary.registerAction({ + name: 'copy_assets', + do: function(dictionary, config) { + console.log('Copying assets directory'); + fs.copySync('assets', config.buildPath + 'assets'); + }, + undo: function(dictionary, config) { + console.log('Cleaning assets directory'); + fs.removeSync(config.buildPath + 'assets'); + } +}); +``` + +* * * + +### registerFormat +> StyleDictionary.registerFormat(format) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Add a custom format to the style dictionary + + +| Param | Type | Description | +| --- | --- | --- | +| format | Object | | +| format.name | String | Name of the format to be referenced in your config.json | +| format.formatter | function | Function to perform the format. Takes 2 arguments, `dictionary` and `config` Must return a string. | + +**Example** +```js +StyleDictionary.registerFormat({ + name: 'json', + formatter: function(dictionary, config) { + return JSON.stringify(dictionary.properties, null, 2); + } +}) +``` + +* * * + +### registerTemplate +> StyleDictionary.registerTemplate(template) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Add a custom template to the Style Dictionary + + +| Param | Type | Description | +| --- | --- | --- | +| template | Object | | +| template.name | String | The name of your template. You will refer to this in your config.json file. | +| template.template | String | Path to your lodash template | + +**Example** +```js +StyleDictionary.registerTemplate({ + name: 'Swift/colors', + template: __dirname + '/templates/swift/colors.template' +}); +``` + +* * * + +### registerTransform +> StyleDictionary.registerTransform(transform) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Add a custom transform to the Style Dictionary +Transforms can manipulate a property's name, value, or attributes + + +| Param | Type | Description | +| --- | --- | --- | +| transform | Object | Transform object | +| transform.type | String | Type of transform, can be: name, attribute, or value | +| transform.name | String | Name of the transformer so a transformGroup can call a list of transforms. | +| [transform.matcher] | function | Matcher function, return boolean if transform should be applied. If you omit the matcher function, it will match all properties. | +| transform.transformer | function | Performs a transform on a property object, should return a string or object depending on the type. Will only update certain properties so you can't mess up property objects on accident. | + +**Example** +```js +StyleDictionary.registerTransform({ + name: 'time/seconds', + type: 'value', + matcher: function(prop) { + return prop.attributes.category === 'time'; + }, + transformer: function(prop) { + // Note the use of prop.original.value, + // before any transforms are performed, the build system + // clones the original property to the 'original' attribute. + return (parseInt(prop.original.value) / 1000).toString() + 's'; + } +}); +``` + +* * * + +### registerTransformGroup +> StyleDictionary.registerTransformGroup(transformGroup) ⇒ [style-dictionary](#module_style-dictionary) + + + + +Add a custom transformGroup to the Style Dictionary, which is a +group of transforms. + + +| Param | Type | Description | +| --- | --- | --- | +| transformGroup | Object | | +| transformGroup.name | String | Name of the transform group that will be referenced in config.json | +| transformGroup.transforms | Array.<String> | Array of strings that reference the name of transforms to be applied in order. Transforms must be defined and match the name or there will be an error at build time. | + +**Example** +```js +StyleDictionary.registerTransformGroup({ + name: 'Swift', + transforms: [ + 'attribute/cti', + 'size/pt', + 'name/cti' + ] +}); +``` + +* * * + diff --git a/docs/assets/build-diagram.png b/docs/assets/build-diagram.png new file mode 100644 index 00000000..7400fc3f Binary files /dev/null and b/docs/assets/build-diagram.png differ diff --git a/docs/assets/css/main.css b/docs/assets/css/main.css new file mode 100644 index 00000000..c4122e59 --- /dev/null +++ b/docs/assets/css/main.css @@ -0,0 +1,42 @@ +.markdown-section iframe[src*="buttons.github.io"] { + margin: 0; +} + +figure.thumbnails img { + margin: 0.75em 0; + border-radius: 3px; + box-shadow: 0 2px 6px rgba(0,0,0,0.1), 0 4px 12px rgba(0,0,0,0.15); +} + +@media (min-width: 30em) { + figure.thumbnails:after { + content: ""; + display: table; + clear: both; + } + + figure.thumbnails img { + float: left; + width: calc(50% - 0.75em); + } + + figure.thumbnails img:nth-child(even) { + margin-left: 1.5em; + } + + @supports (display: flex) { + figure.thumbnails { + display: flex; + align-items: center; + } + + figure.thumbnails img { + flex-grow: 1; + width: 0; + } + + figure.thumbnails img + img { + margin: 0 0 0 1.5em; + } + } +} diff --git a/docs/assets/cti.png b/docs/assets/cti.png new file mode 100644 index 00000000..089f69c7 Binary files /dev/null and b/docs/assets/cti.png differ diff --git a/docs/assets/fake_player.png b/docs/assets/fake_player.png new file mode 100644 index 00000000..94343e65 Binary files /dev/null and b/docs/assets/fake_player.png differ diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 00000000..ca8c5ee4 Binary files /dev/null and b/docs/assets/favicon.png differ diff --git a/docs/assets/js/.eslintrc.js b/docs/assets/js/.eslintrc.js new file mode 100644 index 00000000..36ac1fa7 --- /dev/null +++ b/docs/assets/js/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + "parserOptions": { + "ecmaVersion": 5, + "sourceType": "script" + }, + "env": { + "commonjs": false, + "es6" : false, + "node" : false + }, + "rules": { + "no-var" : "off", + "prefer-const": "off" + } +} \ No newline at end of file diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js new file mode 100644 index 00000000..1029804c --- /dev/null +++ b/docs/assets/js/main.js @@ -0,0 +1,121 @@ +(function() { + // Functions + // ========================================================================= + /** + * Adds event listeners to change active stylesheet and restore previously + * activated stylesheet on reload. + * + * @example + * + * This link: + * Foo + * Will active this existing link: + * + * + * @example + * + * This link: + * Bar + * Will activate this existing link: + * + * Or generate this active link: + * + */ + function initStyleSwitcher() { + var isInitialzed = false; + var sessionStorageKey = 'activeStylesheetHref'; + + function handleSwitch(activeHref, activeTitle) { + var activeElm = document.querySelector('link[href*="' + activeHref +'"],link[title="' + activeTitle +'"]'); + + if (!activeElm && activeHref) { + activeElm = document.createElement('link'); + activeElm.setAttribute('href', activeHref); + activeElm.setAttribute('rel', 'stylesheet'); + activeElm.setAttribute('title', activeTitle); + + document.head.appendChild(activeElm); + + activeElm.addEventListener('load', function linkOnLoad() { + activeElm.removeEventListener('load', linkOnLoad); + setActiveLink(activeElm); + }); + } + else if (activeElm) { + setActiveLink(activeElm); + } + } + + function setActiveLink(activeElm) { + var activeHref = activeElm.getAttribute('href'); + var activeTitle = activeElm.getAttribute('title'); + var inactiveElms = document.querySelectorAll('link[title]:not([href*="' + activeHref +'"]):not([title="' + activeTitle +'"])'); + + // Remove "alternate" keyword + activeElm.setAttribute('rel', (activeElm.rel || '').replace(/\s*alternate/g, '').trim()); + + // Force enable stylesheet (required for some browsers) + activeElm.disabled = true; + activeElm.disabled = false; + + // Store active style sheet + sessionStorage.setItem(sessionStorageKey, activeHref); + + // Disable other elms + for (var i = 0; i < inactiveElms.length; i++) { + var elm = inactiveElms[i]; + + elm.disabled = true; + + // Fix for browsersync and alternate stylesheet updates. Will + // cause FOUC when switching stylesheets during development, but + // required to properly apply style updates when alternate + // stylesheets are enabled. + if (window.browsersyncObserver) { + var linkRel = elm.getAttribute('rel') || ''; + var linkRelAlt = linkRel.indexOf('alternate') > -1 ? linkRel : (linkRel + ' alternate').trim(); + + elm.setAttribute('rel', linkRelAlt); + } + } + + // CSS custom property ponyfil + if ((window.$docsify || {}).themeable) { + window.$docsify.themeable.util.cssVars(); + } + } + + // Event listeners + if (!isInitialzed) { + isInitialzed = true; + + // Restore active stylesheet + document.addEventListener('DOMContentLoaded', function() { + var activeHref = sessionStorage.getItem(sessionStorageKey); + + if (activeHref) { + handleSwitch(activeHref); + } + }); + + // Update active stylesheet + document.addEventListener('click', function(evt) { + var dataHref = evt.target.getAttribute('data-link-href'); + var dataTitle = evt.target.getAttribute('data-link-title') + + if (dataHref || dataTitle) { + dataTitle = dataTitle + || evt.target.textContent + || '_' + Math.random().toString(36).substr(2, 9); // UID + + handleSwitch(dataHref, dataTitle); + evt.preventDefault(); + } + }); + } + } + + // Main + // ========================================================================= + initStyleSwitcher(); +})(); diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 00000000..9715805e Binary files /dev/null and b/docs/assets/logo.png differ diff --git a/docs/assets/styles.css b/docs/assets/styles.css new file mode 100644 index 00000000..aef12471 --- /dev/null +++ b/docs/assets/styles.css @@ -0,0 +1,393 @@ +:root { + --theme-color: #1FC5BF; + --theme-color-light: #99EBE2; + --theme-color-dark: #00B3AC; + --theme-color-secondary: #6A5096; + --theme-color-secondary-dark: #3F1C77; + --theme-color-secondary-light: #C4B2E1; + + --text-color-base: #2E2E46; + --text-color-secondary: #646473; + --text-color-tertiary: #81818E; +} + + +::selection { + background: var(--theme-color-light); +} + +body { + font-size: 100%; + line-height: 1.5; + font-family: 'Source Sans Pro','Open Sans','Helvetica Neue',Arial,sans-serif; + color: var(--text-color-base); +} + +* { + text-decoration: none !important; +} + +a { + transition: all 0.3s linear; +} + +div.search { + border-bottom: 2px solid #787881; + border: none; + background-color: var(--theme-color-secondary-light); + padding: 0; +} + +.sidebar .search input { + background: none; + background-color: rgba(255,255,255,0.5); + padding: 1rem; + transition: background-color 0.3s ease; +} + +.sidebar .search input:focus { + background-color: rgba(255,255,255,1); +} + +aside.sidebar { + border: none; + background-color: var(--theme-color-secondary); + color: #fff; + width: 20%; +} + +body.close .sidebar { + transform: translateX(-100%); +} + +.sidebar ul li a { + color: rgba(255,255,255,0.8); + color: var(--theme-color-light); + font-size: 1rem; +} + +.sidebar ul li.active>a { + border-width: 0.1rem; +} + +.sidebar ul li a:hover { + text-decoration: none; + color: rgba(255,255,255,1); +} + +.sidebar .sidebar-nav ul li.active>a { + color: #fff; + border-right: 0.2rem solid var(--theme-color-secondary-light,#29D0CA); +} + +.search .results-panel.show { + background-color: #05827E; + background-color: #fff; + color: #000; +} + +.sidebar .search .matching-post { + padding: 0; + border-bottom: 0.2rem solid #E4E4E6; +} + +.sidebar .search .matching-post:first-child { + border-top: 0.2rem solid #E4E4E6; +} + +.search .search-keyword { + /* color: #fff; */ +} + +.search a { + padding: 1rem; + display: block; + transition: background-color 0.3s ease; +} + +.search a:hover { + color: var(--theme-color-dark); +} + +.search p.empty { + margin: 0; + padding: 1rem; + background-color: #F1F1F2; +} + +.sidebar > h1 { + font-size: 2rem; +} + +.sidebar-logo { + display: block; + width: 4rem; + vertical-align: bottom; + line-height: 1.6; + height: 4rem; + margin: 0 auto; +} + +body .sidebar-toggle { + background: none; + bottom: 1rem; + left: 1rem; + cursor: pointer; + width: 1.5rem; + height: 1.5rem; + padding: 0; +} + +body .sidebar-toggle span { + transition: all 0.3s linear; + background-color: var(--theme-color-light); + height: 0.25rem; + width: 1.5rem; + position: absolute; + left: 0; + margin: 0; + transform-origin: 0; +} + +body.close .sidebar-toggle { + width: 1.5rem; + height: 1.5rem; +} + +body.close .sidebar-toggle span { + transform-origin: center; +} + +body .sidebar-toggle span:nth-child(1) { top:0; } +body .sidebar-toggle span:nth-child(2) { top:0.65rem; } +body .sidebar-toggle span:nth-child(3) { top:1.25rem; } + +.sidebar-toggle .sidebar-toggle-button:hover { opacity: 1; } + +.sidebar-toggle:hover span:nth-child(1) { transform: rotate(45deg); width: 1.75rem; } +.sidebar-toggle:hover span:nth-child(2) { opacity: 0; } +.sidebar-toggle:hover span:nth-child(3) { transform: rotate(-45deg); width: 1.75rem; } + +.close .sidebar-toggle:hover span:nth-child(1) { transform:rotate(0); width:1.5rem; top:0.65rem; } +.close .sidebar-toggle:hover span:nth-child(2) { opacity: 1; transform:rotate(90deg); } +.close .sidebar-toggle:hover span:nth-child(3) { transform:rotate(0); width:1.5rem; top:0.65rem; } + +th { + text-align: left; +} + +.markdown-section blockquote { + margin: 1em 0; +} + +.markdown-section em, +.markdown-section blockquote { + color: var(--text-color-tertiary); +} + +.cover-main img { + max-width: 10rem; + max-height: 10rem; +} + +section.cover p { + line-height: inherit; +} + +section.cover .cover-main a { + font-weight: 600; +} + +section.cover .cover-main a::before { + display: none; +} + +section.cover .cover-main blockquote { + font-style: italic; + color: #868C91; +} + +section.cover .cover-main>p:last-child a:first-child { + border-width: 0.2rem; + color: var(--theme-color-secondary); + border-color: var(--theme-color-secondary); +} + +section.cover .cover-main>p:last-child a:last-child { + background-color: var(--theme-color-secondary); + border-color: var(--theme-color-secondary); +} + +section.cover .cover-main>p:last-child a:hover { + color: var(--theme-color-secondary-dark); + border-color: var(--theme-color-secondary-dark); + opacity: 1; +} + +section.cover .cover-main>p:last-child a:last-child:hover { + background-color: var(--theme-color-secondary-dark); + border-color: var(--theme-color-secondary-dark); + color: #fff; + opacity: 1; +} + +.anchor { + position: relative; +} + +.anchor::before { + content: '\1F449'; + position: absolute; + top: 0; + left: -1.25em; + opacity: 0; + font-size: 0.875em; +} + +.anchor:hover::before { + opacity: 1; +} + +section.cover .cover-main { + margin: 20vh 20vw; +} + +.app-name-link { + white-space: nowrap; +} + +.app-sub-sidebar li:before { + display: none; +} + +.markdown-section pre, +.markdown-section pre > code { + background-color: #2E2E46; + color: rgba(255,255,255,0.75); + font-size: 1em; + line-height: 1.5; +} + +.markdown-section code { + display: inline-block; + font-family: 'Source Code Pro', monospace; +} + +.markdown-section pre { + padding: 2rem; +} + +.markdown-section pre > code { + padding: 0; +} + +.markdown-section hr { + border-bottom: 5px solid transparent; +} + +.token.punctuation { + color: #585967; +} + +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata{color:#999999;} +.token.property, +.token.number, +.token.function-name, +.token.constant, +.token.symbol, +.token.deleted{color:#5a9bcf;}.token.boolean{color:#ff8b50;}.token.tag{color:#fc929e;}.token.string{color:#8dc891;}.token.punctuation{color:#5FB3B3;} +.token.selector, +.token.char, +.token.builtin, +.token.inserted{color:#D8DEE9;}.token.function{color:#79b6f2;} +.token.operator, +.token.entity, +.token.url, +.token.variable{color:#d7deea;}.token.attr-value{color:#8dc891;}.token.keyword{color:#c5a5c5;} + +.lang-scss .token.variable { + color: #8dc891; +} + +.markdown-section { + max-width: 75rem; + padding: 1rem 3rem; +} + +.markdown-section ol, .markdown-section p, .markdown-section ul { + line-height: inherit; +} + +.markdown-section code { + color: inherit; + border-radius: 0; + font-size: 0.9em; + padding: 6px 10px; + /* color: #111; */ +} + +.markdown-section table { + display: table; +} + +.markdown-section table tr { + border-width: 0.2rem 0; + border-style: solid; + border-color: #F1F1F2; +} + +.markdown-section table tr:nth-child(2n) { + background-color: transparent; +} + +.markdown-section table td, +.markdown-section table th { + border: none; + padding: 1.5rem 0.5rem; + text-align: left; +} + +.markdown-section table td p { + margin: 0; +} + +.markdown-section a { + text-decoration: none; + border-bottom: 0.1rem solid var(--theme-color-light); + transition: all 0.3s ease; +} + +.markdown-section a:hover { + border-color: var(--theme-color); + color: var(--theme-color-dark); +} + + +/* Badges */ +.markdown-section > p:first-child > a { + border: none; +} + +.docsify-copy-code-button { + background: var(--theme-color); +} + +.sidebar::-webkit-scrollbar { + width:0; +} + +@media (min-width: 1200px) { + body { + font-size: 112.5%; + } +} + +@media (min-width: 1400px) { + body { + font-size: 125%; + } +} diff --git a/docs/build_process.md b/docs/build_process.md new file mode 100644 index 00000000..29dab6a2 --- /dev/null +++ b/docs/build_process.md @@ -0,0 +1,42 @@ +# Build Process + +Here is what the build system is doing under the hood. + +![build structure](assets/build-diagram.png) + +## CLI + +1. The build system looks for a config file. By default it looks for config.json in the current directory, or you can specify the config path with the `-c --config` flag. +1. If there is an `includes` attribute in the config, it will take those JSON files and deep merge them into the `properties` object. +1. It then takes all the JSON files in the `source` attribute in the config and performs a deep merge onto the `properties` object. +1. Then it iterates over the platforms in the config and: + 1. Perform all transforms, in order, defined in the transforms attribute or transformGroup. + 1. Build all files defined in the files array + 1. Perform any actions defined in the actions attribute + + +## Node + +If you use this as a node module, the steps are slightly different, but the overall. + +1. When you call the [`extend`](api.md#extend) method, you can either pass it a path to a JSON config file, or give it a plain object that has the configuration. This will perform steps 1-3 above. +1. Then you can now call `buildAllPlatforms` or other methods like `buildPlatform('scss')` or `exportPlatform('javascript')`. This is equivalent to step 4 above. + +```javascript +const StyleDictionary = require('style-dictionary'); + +const styleDictionary = StyleDictionary.extend( 'config.json' ); +// is equivalent to this: +// const styleDictionary = StyleDictionary.extend( +// JSON.parse( fs.readFileSync( 'config.json' ) ) +// ) + +// You can also extend with an object +// const styleDictionary = StyleDictionary.extend({ /* config options */ }); + +// This will perform step 3 above, for each platform: +// 1. Apply transforms +// 2. Build files +// 3. Perform actions +styleDictionary.buildAllPlatforms(); +``` diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..3fc4b972 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,39 @@ +# Examples + +To get you started, there are some example packages included that you can use. You can take a look at the code on Github or you +can use the CLI included to generate a new package using these examples. Here is how you can do that: +```bash +$ mkdir MyStyleD +$ cd MyStyleD +$ style-dictionary init [example] +``` +Where `[example]` is one of: `basic`, `complete`, `npm`, `s3` + +## Basic +[View on Github](https://github.com/amzn/style-dictionary/tree/master/example/basic) + +This example code is bare-bones to show you what this framework can do. Use this if you want to play around with what the Style Dictionary +can do. + + +## Complete +[View on Github](https://github.com/amzn/style-dictionary/tree/master/example/complete) + +This is a more complete package and should have everything you need to get started. This package can be consumed as a Cocoapod on iOS, +as a node module for web, and as a local library for Android. + +## npm +[View on Github](https://github.com/amzn/style-dictionary/tree/master/example/npm) + +This example shows how to set up a style dictionary as an npm module, either to publish to a local npm service or to publish externally. + +When you publish this npm module, the prepublish hook will run, calling the style dictionary build system to create the necessary files. You can also just run `npm run build` to generate the files to see what it is creating. + +## s3 +[View on Github](https://github.com/amzn/style-dictionary/tree/master/example/s3) + +One way to use the style dictionary framework is to build files for each platform and upload those build artifacts to an s3 bucket. The platforms can pull these files down during their build process. + +---- + +> More coming soon... diff --git a/docs/extending.md b/docs/extending.md new file mode 100644 index 00000000..a925726b --- /dev/null +++ b/docs/extending.md @@ -0,0 +1,45 @@ +# Extending + +The style dictionary build system is made to be extended. We don't know exactly how everyone will want to use style dictionaries in their project, which is why it is easy to create custom transforms, templates, and formats. + +* [registerTransform](api.md#registertransform) +* [registerTransformGroup](api.md#registertransformgroup) +* [registerFormat](api.md#registerformat) +* [registerTemplate](api.md#registertemplate) +* [registerAction](api.md#registeraction) + +```javascript +const StyleDictionary = require('style-dictionary').extend('config.json'); + +StyleDictionary.registerTransform({ + name: 'time/seconds', + type: 'value', + matcher: function(prop) { + return prop.attributes.category === 'time'; + }, + transformer: function(prop) { + return (parseInt(prop.original.value) / 1000).toString() + 's'; + } +}); + +StyleDictionary.buildAllPlatforms(); +``` + +You can also export your extended style dictionary as a node module if you need other projects to depend on it. + +```javascript +// package a +const StyleDictionary = require('style-dictionary').extend('config.json'); +StyleDictionary.registerTransform({ + name: 'name/uppercase', + type: 'name', + transformer: function(prop) { + return prop.path.join('_').toUppercase(); + } +}); + +module.exports = StyleDictionary; + +// package b +const StyleDictionary = require('package-a'); +``` diff --git a/docs/formats.md b/docs/formats.md new file mode 100644 index 00000000..2c7019fd --- /dev/null +++ b/docs/formats.md @@ -0,0 +1,271 @@ +# Formats + +Formats are one of the ways to create files that act as interfaces for your style dictionary. For example, you want to be able to +use your style dictionary in CSS. You can use the `css/variables` template which will create a CSS file with variables from +your style dictionary. You can define custom formats with the [`registerFormat`](api.md#registerformat). + +Templates and Formats serve the same purpose: use your style dictionary as data to build a file. You use formats in your config +file under platforms > [platform] > files > [file] + +```json +{ + "source": ["properties/**/*.json"], + "platforms": { + "css": { + "transformGroup": "css", + "files": [ + { + "template": "css/variables", + "destination": "variables.css" + } + ] + } + } +} +``` + + +>*__How are Templates different than Formats?__* + +>Mainly syntactic sugar; anything you can do in a Template you can do in a Format. Use whichever is easier for you to write. We find +that Templates are good if you have a lot of boilerplate code around where the style dictionary will go (like writing ObjectiveC files). +Formats are better if there is little to no boilerplate code like a flat SCSS variables file. + +---- + +## Pre-defined Formats + +[lib/common/formats.js](https://github.com/amzn/style-dictionary/blob/master/lib/common/formats.js) + +### css/variables + + +Creates a CSS file with variable definitions based on the style dictionary + +**Example** +```css +:root { + --color-background-base: #f0f0f0; + --color-background-alt: #eeeeee; +} +``` + +* * * + +### scss/variables + + +Creates a SCSS file with variable definitions based on the style dictionary + +**Example** +```scss +$color-background-base: #f0f0f0; +$color-background-alt: #eeeeee; +``` + +* * * + +### scss/icons + + +Creates a SCSS file with variable definitions and helper classes for icons + +**Example** +```scss +$content-icon-email: '\E001'; +.icon.email:before { content:$content-icon-email; } +``` + +* * * + +### less/variables + + +Creates a LESS file with variable definitions based on the style dictionary + +**Example** +```less +@color-background-base: #f0f0f0; +@color-background-alt: #eeeeee; +``` + +* * * + +### less/icons + + +Creates a LESS file with variable definitions and helper classes for icons + +**Example** +```less +@content-icon-email: '\E001'; +.icon.email:before { content:@content-icon-email; } +``` + +* * * + +### javascript/module + + +Creates a CommonJS module with the whole style dictionary + +**Example** +```js +module.exports = { + color: { + base: { + red: { + value: '#ff000' + } + } + } +} +``` + +* * * + +### javascript/object + + +Creates a JS file a global var that is a plain javascript object of the style dictionary. +Name the variable by adding a 'name' attribute on the file object in your config. + +**Example** +```js +var StyleDictionary = { + color: { + base: { + red: { + value: '#ff000' + } + } + } +} +``` + +* * * + +### javascript/umd + + +Creates a [UMD](https://github.com/umdjs/umd) module of the style +dictionary. Name the module by adding a 'name' attribute on the file object +in your config. + +**Example** +```js +(function(root, factory) { + if (typeof module === "object" && module.exports) { + module.exports = factory(); + } else if (typeof exports === "object") { + exports["_styleDictionary"] = factory(); + } else if (typeof define === "function" && define.amd) { + define([], factory); + } else { + root["_styleDictionary"] = factory(); + } +}(this, function() { + return { + "color": { + "red": { + "value": "#FF0000" + } + } + }; +})) +``` + +* * * + +### javascript/es6 + + +Creates a ES6 module of the style dictionary. You can filter the style dictionary +to only export properties of a certain type by adding a 'filter' attribute on the +file object in the config. + +```json +{ + "platforms": { + "js": { + "files": [ + { + "format": "javascript/es6", + "destination": "colors.js", + "filter": { + "category": "color" + } + } + ] + } + } +} +``` + +**Example** +```js +export const BackgroundBase = '#ffffff'; +export const BackgroundAlt = '#fcfcfcfc'; +``` + +* * * + +### json + + +Creates a JSON file of the style dictionary. + +**Example** +```json +{ + "color": { + "base": { + "red": { + "value": "#ff000" + } + } + } +} +``` + +* * * + +### json/asset + + +Creates a JSON file of just the assets defined in the style dictionary. + +**Example** +```js +{ + "asset": { + "image": { + "logo": { + "value": "assets/logo.png" + } + } + } +} +``` + +* * * + +### sketch/palette + + +Creates a sketchpalette file of all the base colors + +**Example** +```json +{ + "compatibleVersion": "1.0", + "pluginVersion": "1.1", + "colors": [ + "#ffffff", + "#ff0000", + "#fcfcfc" + ] +} +``` + +* * * diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..e9b86f12 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,72 @@ + + + + + M5Stack Documentation - Style once, use everywhere. A build system for creating cross-platform styles. + + + + + + + + + + + + + + + + + + + + +
Loading...
+ + + + + + + + + + + + diff --git a/docs/package_structure.md b/docs/package_structure.md new file mode 100644 index 00000000..5bf8c232 --- /dev/null +++ b/docs/package_structure.md @@ -0,0 +1,120 @@ +# Package Structure + +Style dictionaries are configuration driven. + +Here is a basic example of what a style dictionary package looks like. + +``` +├── config.json +├── properties/ +│ ├── size/ +│ ├── font.json +│ ├── color/ +│ ├── font.json +│ ... +├── assets/ +│ ├── fonts/ +│ ├── images/ +``` + + +## config.json +The default way is to use a config.json file in the root of your package. Here is a quick example: +```json +{ + "source": ["properties/**/*.json"], + "platforms": { + "scss": { + "transformGroup": "scss", + "prefix": "sd", + "buildPath": "build/scss/", + "files": [{ + "destination": "_variables.scss", + "format": "scss/variables" + }], + "actions": ["copy_assets"] + }, + "android": { + "transforms": ["attribute/cti", "name/cti/snake", "color/hex", "size/remToSp", "size/remToDp"], + "buildPath": "build/android/src/main/res/values/", + "files": [{ + "destination": "style_dictionary_colors.xml", + "template": "android/colors" + }] + } + } +} +``` + +| Attribute | Type | Description | +| :--- | :--- | :--- | +| source | Array[String] | An array of paths to JSON files that contain style properties. The Style Dictionary will do a deep merge of all of the JSON files so you can separate your properties into multiple files. | +| platforms | Object | An object containing platform config objects that describe how the Style Dictionary should build for that platform. You can add any arbitrary attributes on this object that will get passed to formats/templates and actions (more on these in a bit). This is useful for things like build paths, name prefixes, variable names, etc. | +| platform.transforms | Array[String] (optional) | An array of [transforms](transforms.md) to be performed on the style properties object. These will transform the properties in a non-desctructive way so each platform can transform the properties. Transforms to apply sequentially to all properties. Can be a built-in one or you can create your own. | +| platform.transformGroup | String (optional) | A string that maps to an array of transforms. This makes it easier to reference transforms by grouping them together. You must either define this or `transforms`. | +| platform.buildPath | String (optional) | Base path to build the files, must end with a trailing slash. | +| platform.files | Array (optional) | Files to be generated for this platform. | +| platform.file.destination | String (optional) | Location to build the file, will be appended to the buildPath. | +| platform.file.format | String (optional) | [Format](formats.md) used to generate the file. Can be a built-in one or you can create your own. Must declare a format or a template. | +| platform.file.template | String (optional) | [Template](templates.md) used to generate the file. Can be a built-in one or you can create your own. | +| platform.actions | Array[String] (optional) | [Actions](actions.md) to be performed after the files are built for that platform. Actions can be any arbitrary code you want to run like copying files, generating assets, etc. You can use pre-defined actions or create custom actions. | + +---- + +## Properties + +Style properties are a collection of JSON files. We usually keep them in a `properties` directory, but you can put them wherever you like, +they just need to be referenced in the `source` attribute on your `config.json` file. + +Style properties are what make up a style dictionary. You can structure your properties however you want to, the only requirement is the property contains a "value" attribute. This is how the build system knows which nodes are properties as opposed to structure. This allows you to have different levels of nesting. + +```json +{ + "color": { + "font": { + "base": { "value": "#111111" }, + "inverse": { + "base": { "value": "#EEEEEE" } + } + } + } +} +``` + +The above JSON snippet has 2 style properties, `color.font.base` and `color.font.inverse.base`. So you can have style properties defined at any level in the JSON structure. + +#### Category / Type / Item + +This is not required by any means, but we feel this classification structure of style properties makes the most sense semantically. Style properties can be organized into a hierarchical tree structure with the top level, category, defining the primitive nature of the property. For example, we have the color category and every property underneath is always a color. As you proceed down the tree, you get more specific about what that color is. Is it a background color, a text color, or a border color? What kind of text color is it? You get the point. It's like the animal kingdom classification: + +![](assets/cti.png) + +Now you can structure your property json files like simple objects: + +```json +{ + "size": { + "font": { + "base": { "value": "16" }, + "large": { "value": "20" } + } + } +} +``` + +The CTI is implicit in the structure, the category is 'size' and the type is 'font', and there are 2 properties 'base' and 'large'. + +Structuring style properties in this manner gives us consistent naming and accessing of these properties. You don't need to remember if it is button_color_error or error_button_color, it is color_background_button_error! + +You can organize and name your style properties however you want, there are no restrictions. But there are a good amount of helpers if you do use this structure, like the 'attribute/cti' transform which adds attributes to the property of its CTI based on the path in the object. There are a lot of name transforms as well for when you want a flat structure like for sass variables. + +Also, the CTI structure provides a good mechanism to target transforms for specific kinds of properties. All of the transforms provided by the framework use the CTI structure to know if it should be applied. For instance, the 'color/hex' transform only applies to properties of the category 'color'. + +---- + +## Assets + +Assets are not required, but can be useful to include in your style dictionary. If you don't want to manage having assets like images, +vectors, font files, etc. in multiple locations, you can keep them in your style dictionary as a single source of truth. + +> Coming soon: how to generate image assets based on your style dictionary diff --git a/docs/quick_start.md b/docs/quick_start.md new file mode 100644 index 00000000..d603b20b --- /dev/null +++ b/docs/quick_start.md @@ -0,0 +1,216 @@ +# Quick Start + +## Installation +*Note that you must have node (and npm) installed.* + +If you want to use the CLI, you can install it globally via npm: +```bash +$ npm install -g style-dictionary +``` + +!> Or you can install it like a normal npm dependency. This is a build tool so you are most likely going to want to save it as a dev dependency: +```bash +$ npm install -D style-dictionary +``` + +If you want to install it with yarn: +```bash +$ yarn add style-dictionary --dev +``` + +## Creating a New Project +The CLI comes with some starter code to get a new project started easily. +```bash +$ mkdir MyStyleD +$ cd MyStyleD +$ style-dictionary init basic +``` + +This command will copy over the example files found in example in this repo and then run the `style-dictionary build` command to generate the build artifacts. You should see something like this output: +``` +Reading config file from ./config.json +Building all platforms + +scss +✔︎ build/scss/_variables.scss + +android +✔︎ build/android/font_dimens.xml + +ios +✔︎ build/ios/StyleDictionaryColor.h +✔︎ build/ios/StyleDictionaryColor.m +``` + +Pat yourself on the back, you just built your first style dictionary! Take a look at what you built. This should have created a build directory and it should look like this: +``` +├── README.md +├── config.json +├── properties/ +│ ├── color/ +│ ├── base.json +│ ├── font.json +│ ├── size/ +│ ├── font.json +│ ├── font.json +├── build/ +│ ├── android/ +│ ├── font_dimens.xml +│ ├── colors.xml +│ ├── scss/ +│ ├── _variables.scss +│ ├── ios/ +│ ├── StyleDictionaryColor.h +│ ├── StyleDictionaryColor.m +``` + +If you open `config.json` you will see there are 3 platforms defined: scss, android, ios. Each platform has a transformGroup, buildPath, and files defined. The buildPath and files of the platform should match up to the files what were built. Those files should look like these: + +**Android** +```xml + + + 12.00sp + 16.00sp + 32.00sp + 16.00sp + + + + + #ffcccccc + #ff999999 + #ff111111 + #ff111111 + #ff999999 + #ffcccccc + +``` + +**SCSS** +```scss +$color-base-gray-light: rgb(204, 204, 204); +$color-base-gray-medium: rgb(153, 153, 153); +$color-base-gray-dark: rgb(17, 17, 17); +$color-font-base: rgb(17, 17, 17); +$color-font-secondary: rgb(153, 153, 153); +$color-font-tertiary: rgb(204, 204, 204); +$size-font-small: 0.75rem; +$size-font-medium: 1rem; +$size-font-large: 2rem; +$size-font-base: 1rem; +``` + +**iOS** +```objectivec +@implementation StyleDictionaryColor + ++ (UIColor *)color:(StyleDictionaryColorName)colorEnum{ + return [[self values] objectAtIndex:colorEnum]; +} + ++ (NSArray *)values { + static NSArray* colorArray; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + colorArray = @[ +[UIColor colorWithRed:0.80f green:0.80f blue:0.80f alpha:1.0f], +[UIColor colorWithRed:0.60f green:0.60f blue:0.60f alpha:1.0f], +[UIColor colorWithRed:0.07f green:0.07f blue:0.07f alpha:1.0f], +[UIColor colorWithRed:0.07f green:0.07f blue:0.07f alpha:1.0f], +[UIColor colorWithRed:0.60f green:0.60f blue:0.60f alpha:1.0f], +[UIColor colorWithRed:0.80f green:0.80f blue:0.80f alpha:1.0f] + ]; + }); + + return colorArray; +} + +@end +``` + +Pretty nifty! This shows a few things happening: +1. The build system does a deep merge of all the property JSON files defined in the `source` attribute of `config.json`. This allows you to split up the property JSON files however you want. There are 2 JSON files with `color` as the top level key, but they get merged properly. +1. The build system resolves references to other style properties. `{size.font.medium.value}` gets resolved properly +1. The build system handles references to property values in other files as well as you can see in `properties/color/font.json` +1. Values get transformed differently depending on the platform they are built to + + +## Making a change + +Now lets make a change and see how that affects things. Open up `properties/color/base.json` and change `"#111111"` to `"#000000"`. After you make that change, save the file and re-run the build command `style-dictionary build`. Open up the build files and take a look. Now + +**Android** +```xml + + + #ffcccccc + #ff999999 + #ff000000 + #ff111111 + #ff999999 + #ffcccccc + +``` +```scss +$color-base-gray-light: rgb(204, 204, 204); +$color-base-gray-medium: rgb(153, 153, 153); +$color-base-gray-dark: rgb(0, 0, 0); +$color-font-base: rgb(0, 0, 0); +$color-font-secondary: rgb(153, 153, 153); +$color-font-tertiary: rgb(204, 204, 204); +``` +```objectivec +[UIColor colorWithRed:0.80f green:0.80f blue:0.80f alpha:1.00f], +[UIColor colorWithRed:0.60f green:0.60f blue:0.60f alpha:1.00f], +[UIColor colorWithRed:0.00f green:0.00f blue:0.00f alpha:1.00f], +[UIColor colorWithRed:0.00f green:0.00f blue:0.00f alpha:1.00f], +[UIColor colorWithRed:0.60f green:0.60f blue:0.60f alpha:1.00f], +[UIColor colorWithRed:0.80f green:0.80f blue:0.80f alpha:1.00f] +``` + +That's it! There is a lot more you can do with your style dictionary than just generate some files with color values. Take a look +at some [examples](examples.md) or take a deeper dive into [package structure](package_structure.md), [extending](extending.md), or how the [build process](build_process.md) works. + +## Basic Usage +### CLI +```bash +$ style-dictionary build +``` +Call this in the root directory of your project. The only thing needed is a `config.json` file. There are also arguments: + +| Flag | Short Flag | Description | +| --- | --- | --- | +| --config \[path\] | -h | Set the config file to use. Must be a .json file | +| --platform \[platform\] | -p | Only build a specific platform defined in the config file. | +| --help | -h | Display help content | +| --version | -v | Display the version | + +### Node +You can also use the style dictionary build system in node if you want to [extend](extending.md) the functionality or use it in another build system like Grunt or Gulp. +```javascript +const StyleDictionary = require('style-dictionary').extend('config.json'); + +StyleDictionary.buildAllPlatforms(); +``` + +The `.extend()` method is an overloaded method that can also take an object with the configuration in the same format as a config.json file. +```javascript +const StyleDictionary = require('style-dictionary').extend({ + source: ['properties/**/*.json'], + platforms: { + scss: { + transformGroup: 'scss', + buildPath: 'build/', + files: [{ + destination: 'variables.scss', + format: 'scss/variables' + }] + } + // ... + } +}); + +StyleDictionary.buildAllPlatforms(); +``` diff --git a/docs/templates.md b/docs/templates.md new file mode 100644 index 00000000..1ed518e5 --- /dev/null +++ b/docs/templates.md @@ -0,0 +1,296 @@ +# Templates + +Templates are one of the ways to create files that act as interfaces for your style dictionary. For example, you want to be able to +use your style dictionary in Android. You can use the `android/colors` template which will create an Anroid resource XML file from +your style dictionary. You can define custom templates with the [`registerTemplate`](api.md#registertemplate). + +Templates and Formats serve the same purpose: use your style dictionary as data to build a file. You use templates in your config +file under platforms > [platform] > files > [file] + +```json +{ + "source": ["properties/**/*.json"], + "platforms": { + "android": { + "transformGroup": "android", + "files": [ + { + "template": "android/colors", + "destination": "colors.xml" + } + ] + } + } +} +``` + +>*__How are Templates different than Formats?__* + +>Mainly syntactic sugar; anything you can do in a Template you can do in a Format. Use whichever is easier for you to write. We find +that Templates are good if you have a lot of boilerplate code around where the style dictionary will go (like writing ObjectiveC files). +Formats are better if there is little to no boilerplate code like a flat SCSS variables file. + +### Using a different templating language + +If you are partial to Handlebars or some other templating language, anything will work as long as there is a node module for it. +All you need to do is register a custom format which calls your template and returns a string. Here is a quick example for Handlebars. + +```js +const StyleDictionary = require('style-dictionary').extend('config.json'); +const Handlebars = require('handlebars'); + +const template = Handlebars.compile( fs.readFileSync('templates/MyTemplate.hbs') ); + +styleDictionary.registerFormat({ + name: 'myTemplate', + formatter: function(dictionary, platform) { + return template({ + properties: dictionary.properties, + options: platform + }); + } +}); + +styleDictionary.buildAllPlatforms(); +``` + +---- + +## Pre-defined Templates + +[lib/common/templates.js](https://github.com/amzn/style-dictionary/blob/master/lib/common/templates.js) + +### android/colors + + +Creates a color resource xml file with all the colors in your style dictionary. + +**Example** +```xml + + + #fffaf3f2 + #fff0cccc + #ffe19d9c +``` + +* * * + +### android/dimens + + +Creates a dimen resource xml file with all the sizes in your style dictionary. + +**Example** +```xml + + + 5.00dp + 10.00dp + 15.00dp +``` + +* * * + +### android/fontDimens + + +Creates a dimen resource xml file with all the font sizes in your style dictionary. + +**Example** +```xml + + + 10.00sp + 13.00sp + 15.00sp +``` + +* * * + +### android/integers + + +Creates a resource xml file with all the integers in your style dictionary. It filters your +style properties by `prop.attributes.category === 'time'` + +**Todo** + +- Update the filter on this. + +**Example** +```xml + + + 1000 + 2000 + 4000 +``` + +* * * + +### android/strings + + +Creates a resource xml file with all the strings in your style dictionary. Filters your +style properties by `prop.attributes.category === 'content'` + +**Example** +```xml + + + + + +``` + +* * * + +### ios/macros + + +Creates an Objective-C header file with macros for style properties + +**Example** +```objectivec +#import +#import + +#define ColorFontLink [UIColor colorWithRed:0.00f green:0.47f blue:0.80f alpha:1.00f] +#define SizeFontTiny 176.00f +``` + +* * * + +### ios/plist + + +Creates an Objective-C plist file + +**Todo** + +- Fix this template and add example and usage + + +* * * + +### ios/singleton.m + + +Creates an Objective-C implementation file of a style dictionary singleton class + +**Todo** + +- Add example and usage + + +* * * + +### ios/singleton.h + + +Creates an Objective-C header file of a style dictionary singleton class + +**Todo** + +- Add example and usage + + +* * * + +### ios/static.h + + +Creates an Objective-C header file of a static style dictionary class + +**Todo** + +- Add example and usage + + +* * * + +### ios/static.m + + +Creates an Objective-C implementation file of a static style dictionary class + +**Todo** + +- Add example and usage + + +* * * + +### ios/colors.h + + +Creates an Objective-C header file of a color class + +**Todo** + +- Add example and usage + + +* * * + +### ios/colors.m + + +Creates an Objective-C implementation file of a color class + +**Todo** + +- Add example and usage + + +* * * + +### ios/strings.h + + +Creates an Objective-C header file of strings + +**Todo** + +- Add example and usage + + +* * * + +### ios/strings.m + + +Creates an Objective-C implementation file of strings + +**Todo** + +- Add example and usage + + +* * * + +### css/fonts.css + + +Creates CSS file with @font-face declarations + +**Todo** + +- Add example and usage + + +* * * + +### static-style-guide/index.html + + +Creates a generic static html page + +**Todo** + +- Add example and usage + + +* * * + diff --git a/docs/transform_groups.md b/docs/transform_groups.md new file mode 100644 index 00000000..9f38f8e4 --- /dev/null +++ b/docs/transform_groups.md @@ -0,0 +1,118 @@ +# Transform Groups + +Transform Groups are a way to easily define and use groups of transforms. They are an array of transforms. You can define custom transform groups with the [`registerTransformGroup`](api.md#registertransformgroup). + +You use transformGroups in your config file under platforms > [platform] > transformGroup + +```json +{ + "source": ["properties/**/*.json"], + "platforms": { + "android": { + "transformGroup": "android" + } + } +} +``` + +---- + +## Pre-defined Transform groups + +[lib/common/transformGroups.js](https://github.com/amzn/style-dictionary/blob/master/lib/common/transformGroups.js) + +### web + + +Transforms: + +[attribute/cti](transforms.md#attributecti) +[name/cti/kebab](transforms.md#namectikebab) +[size/px](transforms.md#sizepx) +[color/css](transforms.md#colorcss) + + +* * * + +### scss + + +Transforms: + +[attribute/cti](transforms.md#attributecti) +[name/cti/kebab](transforms.md#namectikebab) +[time/seconds](transforms.md#timeseconds) +[content/icon](transforms.md#contenticon) +[size/rem](transforms.md#sizerem) +[color/css](transforms.md#colorcss) + + +* * * + +### less + + +Transforms: + +[attribute/cti](transforms.md#attributecti) +[name/cti/kebab](transforms.md#namectikebab) +[time/seconds](transforms.md#timeseconds) +[content/icon](transforms.md#contenticon) +[size/rem](transforms.md#sizerem) +[color/hex](transforms.md#colorhex) + + +* * * + +### html + + +Transforms: + +[attribute/cti](transforms.md#attributecti) +[attribute/color](transforms.md#attributecolor) +[name/human](transforms.md#namehuman) + + +* * * + +### android + + +Transforms: + +[attribute/cti](transforms.md#attributecti) +[name/cti/snake](transforms.md#namectisnake) +[color/hex8android](transforms.md#colorhex8android) +[size/remToSp](transforms.md#sizeremtosp) +[size/remToDp](transforms.md#sizeremtodp) + + +* * * + +### ios + + +Transforms: + +[attribute/cti](transforms.md#attributecti) +[name/cti/pascal](transforms.md#namectipascal) +[color/UIColor](transforms.md#coloruicolor) +[content/objC/literal](transforms.md#contentobjcliteral) +[asset/objC/literal](transforms.md#assetobjcliteral) +[size/remToPt](transforms.md#sizeremtopt) +[font/objC/literal](transforms.md#fontobjcliteral) + + +* * * + +### assets + + +Transforms: + +[attribute/cti](transforms.md#attributecti) + + +* * * + diff --git a/docs/transforms.md b/docs/transforms.md new file mode 100644 index 00000000..49c70d91 --- /dev/null +++ b/docs/transforms.md @@ -0,0 +1,485 @@ +# Transforms + +Transforms are functions that transform a property so that each platform can consume the property in different ways. A simple example is changing pixel values to point values for iOS and dp or sp for Android. Transforms are applied in a non-destructive way so each platform can transform the properties. Transforms are performed sequentially, so the order you use transforms matters. You can define custom transforms with the [`registerTransform`](api.md#registertransform). + +You use transforms in your config file under platforms > [platform] > transforms + +```json +{ + "source": ["properties/**/*.json"], + "platforms": { + "android": { + "transforms": ["attribute/cti", "name/cti/kebab", "color/hex", "size/rem"] + } + } +} +``` + +A transform consists of 4 parts: type, name, matcher, and transformer. Transforms are run on all properties where the matcher returns true. *NOTE: if you don't provide a matcher function, it will match all properties.* + +### Transform Types +There are 3 types of transforms: attribute, name, and value. + +**Attribute:** An attribute transform adds to the attributes object on a property. This is for including any meta-data about a property such as it's CTI or other information. + +**Name:** A name transform transform the name of a property. You should really only be apply one name transformer because they will override each other if you use more than one. + +**Value:** The value transform is the most important as this is the one that changes the representation of the value. Colors can be turned into hex values, rgb, hsl, hsv, etc. Value transforms have a matcher function so that they only get run on certain properties. This allows us to only run a color transform on just the colors and not every property. + +---- + +## Pre-defined Transforms + +[lib/common/transforms.js](https://github.com/amzn/style-dictionary/blob/master/lib/common/transforms.js) + +> All the pre-defined transforms included use the [CTI structure](package_structure.md#properties) for the match properties. If you structure your style properties differently you will need to write [custom transforms](#custom-transforms) or make sure the property CTIs are on the attributes of your properties. + +### attribute/cti + + +Adds: category, type, item, subitem, and state on the attributes object based on the location in the style dictionary. + +```js +// Matches: all +// Returns: +{ + "category": "color", + "type": "background", + "item": "button", + "subitem": "primary", + "state": "active" +} +``` + + +* * * + +### attribute/color + + +Adds: hex, hsl, hsv, rgb, red, blue, green. + +```js +// Matches: prop.attributes.category === 'color' +// Returns +{ + "hex": "009688", + "rgb": {"r": 0, "g": 150, "b": 136, "a": 1}, + "hsl": {"h": 174.4, "s": 1, "l": 0.294, "a": 1}, + "hsv": {"h": 174.4, "s": 1, "l": 0.588, "a": 1}, +} +``` + + +* * * + +### name/human + + +Creates a human-friendly name + +```js +// Matches: All +// Returns: +"button primary" +``` + + +* * * + +### name/cti/camel + + +Creates a camel case name. If you define a prefix on the platform in your config, it will prepend with your prefix + +```js +// Matches: all +// Returns: +"colorBackgroundButtonPrimaryActive" +"prefixColorBackgroundButtonPrimaryActive" +``` + + +* * * + +### name/cti/kebab + + +Creates a kebab case name. If you define a prefix on the platform in your config, it will prepend with your prefix + +```js +// Matches: all +// Returns: +"color-background-button-primary-active" +"prefix-color-background-button-primary-active" +``` + + +* * * + +### name/cti/snake + + +Creates a snake case name. If you define a prefix on the platform in your config, it will prepend with your prefix + +```js +// Matches: all +// Returns: +"color_background_button_primary_active" +"prefix_color_background_button_primary_active" +``` + + +* * * + +### name/cti/constant + + +Creates a constant-style name based on the full CTI of the property. If you define a prefix on the platform in your config, it will prepend with your prefix + +```js +// Matches: all +// Returns: +"COLOR_BACKGROUND_BUTTON_PRIMARY_ACTIVE" +"PREFIX_COLOR_BACKGROUND_BUTTON_PRIMARY_ACTIVE" +``` + + +* * * + +### name/ti/constant + + +Creates a constant-style name on just the type and item of the property. This is useful if you want to create different static classes/files for categories like `Color.BACKGROUND_BASE`. If you define a prefix on the platform in your config, it will prepend with your prefix. + +```js +// Matches: all +// Returns: +"BACKGROUND_BUTTON_PRIMARY_ACTIVE" +"PREFIX_BACKGROUND_BUTTON_PRIMARY_ACTIVE" +``` + + +* * * + +### name/cti/pascal + + +Creates a Pascal case name. If you define a prefix on the platform in your config, it will prepend with your prefix + +```js +// Matches: all +// Returns: +"ColorBackgroundButtonPrimaryActive" +"PrefixColorBackgroundButtonPrimaryActive" +``` + + +* * * + +### color/rgb + + +Transforms the value into an RGB string + +```js +// Matches: prop.attributes.category === 'color' +// Returns: +"rgb(0, 150, 136)" +``` + + +* * * + +### color/hex + + +Transforms the value into an 6-digit hex string + +```js +// Matches: prop.attributes.category === 'color' +// Returns: +"#009688" +``` + + +* * * + +### color/hex8 + + +Transforms the value into an 8-digit hex string + +```js +// Matches: prop.attributes.category === 'color' +// Returns: +"#009688ff" +``` + + +* * * + +### color/hex8android + + +Transforms the value into an 8-digit hex string for Android because they put the alpha channel first + +```js +// Matches: prop.attributes.category === 'color' +// Returns: +"#ff009688" +``` + + +* * * + +### color/UIColor + + +Transforms the value into an UIColor class for iOS + +```objectivec +// Matches: prop.attributes.category === 'color' +// Returns: +[UIColor colorWithRed:0.00f green:0.59f blue:0.53f alpha:1.0f] +``` + + +* * * + +### color/css + + +Transforms the value into a hex or rgb string depending on if it has transparency + +```css +// Matches: prop.attributes.category === 'color' +// Returns: +#000000 +rgba(0,0,0,0.5) +``` + + +* * * + +### size/sp + + +Transforms the value into a scale-independent pixel (sp) value for font sizes on Android. It will not scale the number. + +```js +// Matches: prop.attributes.category === 'size' && prop.attributes.type === 'font' +// Returns: +"10.0sp" +``` + + +* * * + +### size/dp + + +Transforms the value into a density-independent pixel (dp) value for non-font sizes on Android. It will not scale the number. + +```js +// Matches: prop.attributes.category === 'size' && prop.attributes.type !== 'font' +// Returns: +"10.0dp" +``` + + +* * * + +### size/remToSp + + +Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes on Android. It WILL scale the number by a factor of 16 (common base font size on web). + +```js +// Matches: prop.attributes.category === 'size' && prop.attributes.type === 'font' +// Returns: +"16.0sp" +``` + + +* * * + +### size/remToDp + + +Transforms the value from a REM size on web into a density-independent pixel (dp) value for font sizes on Android. It WILL scale the number by a factor of 16 (common base font size on web). + +```js +// Matches: prop.attributes.category === 'size' && prop.attributes.type !== 'font' +// Returns: +"16.0dp" +``` + + +* * * + +### size/px + + +Adds 'px' to the end of the number. Does not scale the number + +```js +// Matches: prop.attributes.category === 'size' +// Returns: +"10px" +``` + + +* * * + +### size/rem + + +Adds 'rem' to the end of the number. Does not scale the number + +```js +// Matches: prop.attributes.category === 'size' +// Returns: +"10rem" +``` + + +* * * + +### size/remToPt + + +Scales the number by 16 (default web font size) and adds 'pt' to the end. + +```js +// Matches: prop.attributes.category === 'size' +// Returns: +"16pt" +``` + + +* * * + +### size/remToPx + + +Scales the number by 16 (default web font size) and adds 'px' to the end. + +```js +// Matches: prop.attributes.category === 'size' +// Returns: +"16px" +``` + + +* * * + +### content/icon + + +Takes a unicode point and transforms it into a form CSS can use. + +```js +// Matches: prop.attributes.category === 'content' && prop.attributes.type === 'icon' +// Returns: +"'\\E001'" +``` + + +* * * + +### content/quote + + +Wraps the value in a single quoted string + +```js +// Matches: prop.attributes.category === 'content' +// Returns: +"'string'" +``` + + +* * * + +### content/objC/literal + + +Wraps the value in a double-quoted string and prepends an '@' to make a string literal. + +```objectivec +// Matches: prop.attributes.category === 'content' +// Returns: + +**"string"**: ``` + +* * * + +### font/objC/literal + + +Wraps the value in a double-quoted string and prepends an '@' to make a string literal. + +```objectivec +// Matches: prop.attributes.category === 'font' +// Returns: @"string" +``` + + +* * * + +### time/seconds + + +Assumes a time in miliseconds and transforms it into a decimal + +```js +// Matches: prop.attributes.category === 'time' +// Returns: +"0.5s" +``` + + +* * * + +### asset/base64 + + +Wraps the value in a double-quoted string and prepends an '@' to make a string literal. + +```js +// Matches: prop.attributes.category === 'asset' +// Returns: +'IyBlZGl0b3Jjb25maWcub3JnCnJvb3QgPSB0cnVlCgpbKl0KaW5kZW50X3N0eWxlID0gc3BhY2UKaW5kZW50X3NpemUgPSAyCmVuZF9vZl9saW5lID0gbGYKY2hhcnNldCA9IHV0Zi04CnRyaW1fdHJhaWxpbmdfd2hpdGVzcGFjZSA9IHRydWUKaW5zZXJ0X2ZpbmFsX25ld2xpbmUgPSB0cnVlCgpbKi5tZF0KdHJpbV90cmFpbGluZ193aGl0ZXNwYWNlID0gZmFsc2U=' +``` + + +* * * + +### asset/path + + +Prepends the local file path + +```js +// Matches: prop.attributes.category === 'asset' +// Returns: +"path/to/file/asset.png" +``` + + +* * * + +### asset/objC/literal + + +Wraps the value in a double-quoted string and prepends an '@' to make a string literal. + +```objectivec +// Matches: prop.attributes.category === 'asset' +// Returns: @"string" +``` + + +* * * +