diff --git a/README.md b/README.md index c325aa3..8ba8e97 100644 --- a/README.md +++ b/README.md @@ -17,412 +17,7 @@ This has a positive effect that ranges from giving the colours in your design sy - **With npm:** `npm install @chrisburnell/bowhead` - **Direct download:** [https://github.com/chrisburnell/bowhead/archive/master.zip](https://github.com/chrisburnell/bowhead/archive/master.zip) -## What are "types of values"? - -```css -selector { - property: value; -} -``` - -An important first step to using *Bowhead* is to understand how it organises CSS properties into different "types". By and large, this is done by looking at what the *expected* values for a given property are: - -```css -selector { - background-color: #b22222; - color: #3cb371; - outline-color: #d2b48c; - - padding: 0.5rem; - margin: 2rem; - - display: flex; - align-items: flex-start; - justify-content: flex-end; -} -``` - -If we take the above snippet as an example, we can quickly identify two "types" of values present: colors and measures. *Colors* typically stand out quite easily, and, historically, developers have done well to assign colors to variables to simplify their use throughout the codebase. *Measures* (or *sizes*), on the other hand, are rarely seen reflected as design tokens in *CSS* despite their frequent prescence in other forms of design tokens, e.g. the space around a logo or iconography is usually defined in a brand's guidelines. - -Despite being presented in different formats, we can confidently say that `background-color`, `color`, and `outline-color` expect a *color*-type value, not just because "color" is in their names, but because we can interchange the values between the properties and they still make sense. - -Measures can take trickier forms to identify and categorise, and I recommend allowing for more measures than you might expect at first and paring it back later. Getting everything categorised is the hard part; swapping tokens later becomes very trivial off the back of this up-front effort. Regardless, I attach any kind of distance-related value to a measure, and, once again, we could interchange any of the values between `padding`, `margin`, `border-width`, or `width` and the CSS still makes sense. - -Extrapolating from here across the vast variety of CSS *properties* and the *types of values* they expect, you end up with a map of *most properties* against value types: - - - - - - - - - - - - - - - - - -
colormeasurealignment
- background-color
- border-color
- outline-color
- color
- fill
- stroke
- -
- width
- height
- padding
- margin
- border-width
- min-width
- max-width
- -
- align-items
- justify-content
- -
- -With this knowledge under our belt, we can begin to define the design tokens for our particular project by fleshing out what *values* are available underneath each *type*: - - - - - - - - - - - - - - - - - -
colormeasurealignment
- #b22222
- #3cb371
- #d2b48c
- -
- 1em
- 20px
- 2px
- -
- flex-start
- flex-end
- center
- -
- -## Usage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ValuesDescription
$bowhead-variable-as-default
(optional)
- true (default)
- false -
Decides whether or not use the CSS Variable or raw value when calling the @v function.
$bowhead-show-fallback
(optional)
- true (default)
- false -
Decides whether or not to show a fallback value for the CSS Variable. Only works when $bowhead-variable-as-default is also true.
$bowhead-generate
(optional)
- true (default)
- false -
Decides whether or not to generate CSS Variables for you.
$bowhead-property-map
(optional)
See below.Defines which "types of values" each CSS property should map against.
$bowhead-tokensSee below.Defines the design token values, categorised by "types of values".
- -### Variable As Default - -```scss -$bowhead-variable-as-default: true; -body { - color: v(color, brick); -} -``` - -```css -body { - color: var(--color-brick); -} -``` - -```scss -$bowhead-variable-as-default: false; -body { - color: v(color, brick); -} -``` - -```css -body { - color: #b22222; -} -``` - -### Show Fallback Value - -```scss -$bowhead-variable-as-default: true; -$bowhead-show-fallback: true; -body { - @include v(color, desert); -} -``` - -```css -body { - color: #d2b48c; - color: var(--color-desert); -} -``` - -```scss -$bowhead-variable-as-default: true; -$bowhead-show-fallback: false; -body { - @include v(color, desert); -} -``` - -```css -body { - color: var(--color-desert); -} -``` - -When $bowhead-variable-as-default is false, $bowhead-show-fallback has no effect. - -```scss -$bowhead-variable-as-default: false; -$bowhead-show-fallback: true; -body { - @include v(color, desert); -} -``` - -```css -body { - color: #d2b48c; -} -``` - -```scss -$bowhead-variable-as-default: false; -$bowhead-show-fallback: false; -body { - @include v(color, desert); -} -``` - -```css -body { - color: #d2b48c; -} -``` - -### Generating CSS Variables - -```scss -$bowhead-generate: true; -``` - -```css -:root { - --measure-small: 0.5rem; - --measure-medium: 1rem; - --measure-large: 2rem; - --color-brick: #b22222; - --color-plankton: #3cb371; - --color-desert: #d2b48c; - --opacity-alpha: 0.8; - --opacity-beta: 0.5; - --opacity-gamma: 0.2; - --z-index-below: -1; - --z-index-root: 0; - --z-index-default: 1; - --z-index-above: 2; -} -``` - -```scss -$bowhead-generate: false; -``` - -Nothing is generated! - -### Property Map - -`$bowhead-property-map` is another `map` that contains mappings from CSS properties (`padding-left`, `border-bottom-right-radius`, etc.) to our defined design token "types" (`measure`, `color`, etc.), i.e. - -```scss -$bowhead-property-map: ( - width: measure, - min-width: measure, - max-width: measure, - height: measure, - min-height: measure, - max-height: measure, - ... -) -``` - -If you wish, you can create new mappings or overwrite existing defaults by defining your own property map, e.g. - -```scss -$bowhead-property-map: ( - vertical-align: alignments -); -``` - -Where `alignments` would be one of your design token "types", e.g. - -```scss -$bowhead-tokens: ( - alignments: ( - default: baseline, - alternate: middle - ), - ... -); -``` - -**Bowhead** will merge new types in your defined map into its own defaults automatically! Any that you re-declare will overwrite what exists as a default from *Bowhead*. - -### Tokens - -`$bowhead-tokens` expects an *SCSS* `map` of "types" of tokens. These types could be a *measure*, *color*, *opacity*, *z-index*, etc. - -```scss -$bowhead-tokens: ( - measure: ( - small: 0.5rem, - medium: 1rem, - large: 2rem, - ), - color: ( - brick: #b22222, - plankton: #3cb371, - desert: #d2b48c - ), - opacity: ( - alpha: 0.8, - beta: 0.5, - gamma: 0.2 - ), - z-index: ( - below: -1, - root: 0, - default: 1, - above: 2 - ) -); -``` - --------- - -Then you’ll have to include **Bowhead** in your SCSS somehow. You could use *Webpack* or something like that, or if you’re using *npm*, the below code snippet should suffice. - -Take note that you need to define any of your **Bowhead** variables (`$bowhead-tokens`, `$bowhead-show-fallback`, `$bowhead-generate`(, `$bowhead-property-map`)) before importing **Bowhead** into your SCSS! - -```scss -$bowhead-tokens: ( - ... -); -$bowhead-show-fallback: true; -$bowhead-generate: true; -$bowhead-property-map: ( - ... -); - -@import "node_modules/@chrisburnell/bowhead/bowhead"; -``` - -Finally, you can use either **Bowhead's** `@v` function, `@v` mixin, both, or just the CSS Variables it can spit out. However you use it is totally up to you! :) - -```scss -.thing { - @include v(background-color, desert); - @include v(color, brick); - border: v(measure, small) solid v(color, plankton); - padding: v(measure, medium) v(measure, large); - @include v(z-index, above); - opacity: var(--opacity-alpha); - // 1. if you just want the raw value, this is not really recommended: - text-decoration-color: map-get(map-get($bowhead-tokens, "color"), "brick"); - // 2. this does the same for you: - text-decoration-color: v(color, brick, true); - // 3. so does this, although it includes the CSS Variable too: - @include v(text-decoration-color, brick, true); -} -``` - -will generate… - -```css -.thing { - background-color: #d2b48c; - background-color: var(--color-desert); - color: #b22222; - color: var(--color-brick); - border: var(--measure-small) solid var(--color-plankton); - padding: var(--measure-medium) var(--measure-large); - z-index: 2; - z-index: var(--z-index-above); - opacity: var(--opacity-alpha); - /* 1 */ - text-decoration-color: #b22222; - /* 2 */ - text-decoration-color: #b22222; - /* 3 */ - text-decoration-color: #b22222; - text-decoration-color: var(--color-brick); -} -``` - -## Learn more - -I wrote more about **Bowhead** here: [https://chrisburnell.com/bowhead/](https://chrisburnell.com/bowhead/). +## [Read the full Bowhead documentation on chrisburnell.com](https://chrisburnell.com/bowhead/). ## Authors diff --git a/package-lock.json b/package-lock.json index 42b2661..07988d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@chrisburnell/bowhead", - "version": "0.2.1", + "version": "0.2.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@chrisburnell/bowhead", - "version": "0.2.1", + "version": "0.2.2", "license": "MIT", "devDependencies": { - "sass": "^1.26.10" + "sass": "^1.49.9" } }, "node_modules/anymatch": { @@ -105,6 +105,12 @@ "node": ">= 6" } }, + "node_modules/immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -181,18 +187,29 @@ } }, "node_modules/sass": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.38.1.tgz", - "integrity": "sha512-Lj8nPaSYOuRhgqdyShV50fY5jKnvaRmikUNalMPmbH+tKMGgEKVkltI/lP30PEfO2T1t6R9yc2QIBLgOc3uaFw==", + "version": "1.49.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", + "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", "dev": true, "dependencies": { - "chokidar": ">=3.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/to-regex-range": { @@ -275,6 +292,12 @@ "is-glob": "^4.0.1" } }, + "immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -327,14 +350,22 @@ } }, "sass": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.38.1.tgz", - "integrity": "sha512-Lj8nPaSYOuRhgqdyShV50fY5jKnvaRmikUNalMPmbH+tKMGgEKVkltI/lP30PEfO2T1t6R9yc2QIBLgOc3uaFw==", + "version": "1.49.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", + "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", "dev": true, "requires": { - "chokidar": ">=3.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" } }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 748a54d..cd7f6e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chrisburnell/bowhead", - "version": "0.2.2", + "version": "0.3.0", "description": "Memorable and maintainable design tokens in SCSS", "main": "bowhead.scss", "scripts": { @@ -8,7 +8,7 @@ }, "dependencies": {}, "devDependencies": { - "sass": "^1.26.10" + "sass": "^1.49.9" }, "license": "MIT", "author": "Chris Burnell", diff --git a/src/_config.scss b/src/_config.scss index 3d68224..8e41ee0 100644 --- a/src/_config.scss +++ b/src/_config.scss @@ -8,78 +8,77 @@ $bowhead-show-fallback: true !default; // Decides whether or not to generate CSS Variables for you. $bowhead-generate: true !default; -$bowhead-tokens: () !default; - +// Defines to which types of values properties should map. $bowhead-property-map: () !default; $bowhead-property-map: map-merge( ( - width: measure, - inline-size: measure, - min-width: measure, - min-inline-size: measure, - max-width: measure, - max-inline-size: measure, - height: measure, - block-size: measure, - min-height: measure, - min-block-size: measure, - max-height: measure, - max-block-size: measure, - padding: measure, - padding-block: measure, - padding-inline: measure, - padding-top: measure, - padding-block-start: measure, - padding-right: measure, - padding-inline-end: measure, - padding-bottom: measure, - padding-block-end: measure, - padding-left: measure, - padding-inline-start: measure, - margin: measure, - margin-block: measure, - margin-inline: measure, - margin-top: measure, - margin-block-start: measure, - margin-right: measure, - margin-inline-end: measure, - margin-bottom: measure, - margin-block-end: measure, - margin-left: measure, - margin-inline-start: measure, - outline-offset: measure, - flex-basis: measure, - gap: measure, - grid-gap: measure, - column-gap: measure, - row-gap: measure, - top: measure, - bottom: measure, - left: measure, - right: measure, - border-width: measure, - border-block: measure, - border-inline: measure, - border-top-width: measure, - border-block-start-width: measure, - border-right-width: measure, - border-inline-start-width: measure, - border-bottom-width: measure, - border-block-end-width: measure, - border-left-width: measure, - border-inline-end-width: measure, - outline-width: measure, - text-decoration-thickness: measure, - text-underline-offset: measure, - border-radius: measure, - border-top-left-radius: measure, - border-start-start-radius: measure, - border-top-right-radius: measure, - border-start-end-radius: measure, - border-bottom-right-radius: measure, - border-end-end-radius: measure, - border-bottom-left-radius: measure, - border-end-start-radius: measure, + width: size, + inline-size: size, + min-width: size, + min-inline-size: size, + max-width: size, + max-inline-size: size, + height: size, + block-size: size, + min-height: size, + min-block-size: size, + max-height: size, + max-block-size: size, + padding: size, + padding-block: size, + padding-inline: size, + padding-top: size, + padding-block-start: size, + padding-right: size, + padding-inline-end: size, + padding-bottom: size, + padding-block-end: size, + padding-left: size, + padding-inline-start: size, + margin: size, + margin-block: size, + margin-inline: size, + margin-top: size, + margin-block-start: size, + margin-right: size, + margin-inline-end: size, + margin-bottom: size, + margin-block-end: size, + margin-left: size, + margin-inline-start: size, + outline-offset: size, + flex-basis: size, + gap: size, + grid-gap: size, + column-gap: size, + row-gap: size, + top: size, + bottom: size, + left: size, + right: size, + border-width: size, + border-block: size, + border-inline: size, + border-top-width: size, + border-block-start-width: size, + border-right-width: size, + border-inline-start-width: size, + border-bottom-width: size, + border-block-end-width: size, + border-left-width: size, + border-inline-end-width: size, + outline-width: size, + text-decoration-thickness: size, + text-underline-offset: size, + border-radius: size, + border-top-left-radius: size, + border-start-start-radius: size, + border-top-right-radius: size, + border-start-end-radius: size, + border-bottom-right-radius: size, + border-end-end-radius: size, + border-bottom-left-radius: size, + border-end-start-radius: size, background-color: color, accent-color: color, caret-color: color, @@ -110,6 +109,16 @@ $bowhead-property-map: map-merge( border-left-style: border-style, border-inline-end-style: border-style, outline-style: border-style, + align-content: alignment, + align-items: alignment, + align-self: alignment, + justify-content: alignment, ), $bowhead-property-map ); + +// Allows remapping for custom naming of types. +$bowhead-type-map: () !default; + +// Begin with an empty map. +$bowhead-tokens: () !default; diff --git a/src/_functions.scss b/src/_functions.scss index 90bc3ec..f927d72 100644 --- a/src/_functions.scss +++ b/src/_functions.scss @@ -5,13 +5,13 @@ /// /// @param {String} $property - key from $bowhead-property-map or $bowhead-tokens /// @param {String} $value [default] - key from inner map -/// @param {Boolean} $fallback [false] - toggles the computed fallabck value +/// @param {Boolean} $fallback [not $bowhead-variable-as-default] - toggles the computed fallback value /// /// @example scss -/// padding: v(measure, small) v(measure, medium); -/// // padding: var(--measure-small) var(--measure-medium); +/// padding: v(size, small) v(size, medium); +/// // padding: var(--size-small) var(--size-medium); /// @example scss -/// padding: v(measure, small, true) v(measure, medium, true); +/// padding: v(size, small, true) v(size, medium, true); /// // padding: 0.625rem 1.25rem; /// /// @throw Error if $property doesn't exist in $property @@ -19,81 +19,81 @@ /// /// @return Associated CSS Variable or SCSS value /// -@function v( - $property, - $value: default, - $fallback: not $bowhead-variable-as-default -) { - $generic-values: auto, inherit, initial, none, revert, unset, 0, 1, 100%, - currentColor; - @if (index($generic-values, $value)) { +@function v($property, $value: default, $fallback: not $bowhead-variable-as-default) { + // if a generic value is passed, we can just return the value itself + $generic-values: auto, inherit, initial, none, revert, unset, 0, 1, 100%, currentColor; + @if index($generic-values, $value) { @return $value; - } @else { - // if we're passing in a key in the tokens Map (e.g. measure) - @if map-has-key($bowhead-tokens, $property) { - $map-variables: map-get($bowhead-tokens, $property); + } + // if we're passing in a key in the tokens Map (e.g. size) + @if map-has-key($bowhead-tokens, $property) { + $map-values: map-get($bowhead-tokens, $property); - // throw a warning if the value does not exist in the associated Map - @if not map-has-key($map-variables, $value) { - @warn "There is no value named `#{$value}` in the variable list. The value should be one of `#{map-keys($map-variables)}`."; - } + // throw a warning if the value does not exist in the associated Map + @if not map-has-key($map-values, $value) { + @warn "There is no value named `#{$value}` in the variable list. The value should be one of `#{map-keys($map-values)}`."; + } - @if $fallback { - @return map-get($map-variables, $value); - } @else { - @return var(--#{$property}-#{$value}); - } + @if $fallback { + @return map-get($map-values, $value); + } @else { + @return var(--#{$property}-#{$value}); } - // otherwise we're passing in a value from the properties Map (e.g. fill) - @else if map-has-key($bowhead-property-map, $property) { - $map-properties: map-get($bowhead-property-map, $property); - $nest-name: null; - $nest-map-name: null; - $map: null; - $variable-fallback: null; - $variable-output: null; + } + // otherwise we're passing in a value from the properties Map (e.g. fill) + @else if map-has-key($bowhead-property-map, $property) { + $map-properties: map-get($bowhead-property-map, $property); + $nest-name: null; + $nest-map-name: null; + $map: null; + $variable-fallback: null; + $variable-output: null; - // if a Nested List, we need to go deeper - @if type-of($map-properties) == list { - $nest-name: nth($map-properties, 1); - $nest-map-name: nth($map-properties, 2); - } + // if a Nested List, we need to go deeper + @if type-of($map-properties) == list { + $nest-name: nth($map-properties, 1); + $nest-map-name: nth($map-properties, 2); + } - // if it is a Nested List - @if $nest-name { - // get the map from nested map-name - $map: map-get($bowhead-tokens, $nest-name); - // get the nested map - $nest-map: map-get($map, $nest-map-name); + // if it is a Nested List + @if $nest-name { + @warn "DOES THIS EVER HAPPEN??"; - // throw a warning if the value does not exist - @if not map-has-key($nest-map, $value) { - @warn "There is no value named `#{$value}` in the `#{$nest-name}` variable list. The value should be one of `#{map-keys($nest-map)}`."; - } + // get the map from nested map-name + $map: map-get($bowhead-tokens, $nest-name); + // get the nested map + $nest-map: map-get($map, $nest-map-name); - @if $fallback { - @return map-get($nest-map, $value); - } @else { - @return var(--#{$nest-name}-#{$nest-map-name}-#{$value}); - } + // throw a warning if the value does not exist + @if not map-has-key($nest-map, $value) { + @warn "There is no value named `#{$value}` in the `#{$nest-name}` variable list. The value should be one of `#{map-keys($nest-map)}`."; + } + + @if $fallback { + @return map-get($nest-map, $value); } @else { - // get the map from map name - $map: map-get($bowhead-tokens, $map-properties); + @return var(--#{$nest-name}-#{$nest-map-name}-#{$value}); + } + } @else { + // remap for custom naming of types + @if map-has-key($bowhead-type-map, $map-properties) { + $map-properties: map-get($bowhead-type-map, $map-properties); + } + // get the map from map name, stored + $map: map-get($bowhead-tokens, $map-properties); - // throw a warning if the value does not exist - @if not map-has-key($map, $value) { - @warn "There is no value named `#{$value}` in the `#{$map-properties}` variable map. The value should be one of `#{map-keys($map)}`."; - } + // throw a warning if the value does not exist + @if not map-has-key($map, $value) { + @warn "There is no value named `#{$value}` in the `#{$map-properties}` variable map. The value should be one of `#{map-keys($map)}`."; + } - @if $fallback { - @return map-get($map, $value); - } @else { - @return var(--#{$map-properties}-#{$value}); - } + @if $fallback { + @return map-get($map, $value); + } @else { + @return var(--#{$map-properties}-#{$value}); } - } @else { - // throw a warning if the property does not exist - @warn "There is no property named `#{$property}` in the variable or property map. The value should be one of `#{map-keys(map-merge($bowhead-tokens, $bowhead-property-map))}`."; } } + // throw a warning if the property does not exist + @warn "There is no property named `#{$property}` in the variable or property map. The value should be one of `#{map-keys(map-merge($bowhead-tokens, $bowhead-property-map))}`."; } diff --git a/src/_mixins.scss b/src/_mixins.scss index 7829c13..860658d 100644 --- a/src/_mixins.scss +++ b/src/_mixins.scss @@ -9,11 +9,11 @@ /// /// @example scss /// @include v(padding, small); -/// // padding: var(--measure-small); +/// // padding: var(--size-small); /// @example scss /// @include v(padding, small, true); /// // padding: 0.625rem; -/// // padding: var(--measure-small); +/// // padding: var(--size-small); /// /// @return Associated property and CSS Variable or SCSS value ///