postcss-tidy-columns
Advanced tools
Comparing version 0.4.0-beta1 to 0.4.0-beta2
# Change Log | ||
This project adheres to [Semantic Versioning](http://semver.org/). | ||
## 0.3.4 | ||
**Fixed** | ||
- Fixes an issue where only the first of multiple `tidy-` functions in the same declaration value was being processed (#22) | ||
## 0.3.3 | ||
@@ -5,0 +11,0 @@ |
@@ -47,3 +47,2 @@ const { varPattern } = require('./lib/normalize-options'); | ||
this.fullWidthRule = null; | ||
this.shouldAddGapDecl = false; | ||
this.nonValues = [undefined, 0]; | ||
@@ -50,0 +49,0 @@ |
19
index.js
@@ -39,3 +39,3 @@ const postcss = require('postcss'); | ||
const { fullWidthRule, shouldAddGapDecl } = tidy; | ||
const { fullWidthRule } = tidy; | ||
const { siteMax } = tidy.grid.options; | ||
@@ -65,19 +65,2 @@ | ||
} | ||
/** | ||
* Add the margin declaration here in order to maintain expected source order. | ||
* This is the :last-of-type override for the gap margins. | ||
*/ | ||
if (shouldAddGapDecl) { | ||
rule.parent.insertAfter(rule, cleanClone( | ||
rule, | ||
{ | ||
selector: `${rule.selector}:last-of-type`, | ||
}, | ||
).append({ | ||
prop: 'margin-right', | ||
value: '0', | ||
source: tidy.declarationSource, | ||
})); | ||
} | ||
}); | ||
@@ -84,0 +67,0 @@ }, |
@@ -72,7 +72,2 @@ const { strings, objectsByProperty } = require('./utils/sort'); | ||
// `addGap` should be Boolean. | ||
if ('addGap' === key && undefined !== option) { | ||
acc[key] = ('true' === String(option)); | ||
} | ||
// These should all be valid, positive CSS length values. | ||
@@ -79,0 +74,0 @@ if (['gap', 'edge', 'siteMax'].includes(key) && LENGTH_REGEX.test(option)) { |
@@ -77,13 +77,4 @@ const { normalizeOptions, varPattern } = require('./normalize-options'); | ||
if ('gap' === property) { | ||
// Split the `gap` and `addGap`. | ||
const [gap, addGap] = value.split('/'); | ||
acc[property] = value.trim(); | ||
acc[property] = gap.trim(); | ||
// This is either `undefined` or a string. | ||
acc.addGap = undefined === addGap ? undefined : addGap.trim(); | ||
} else { | ||
acc[property] = value.trim(); | ||
} | ||
return acc; | ||
@@ -108,3 +99,2 @@ }, {}); | ||
gap: undefined, | ||
addGap: false, | ||
siteMax: undefined, | ||
@@ -111,0 +101,0 @@ edge: undefined, |
@@ -15,53 +15,58 @@ /* eslint-disable no-param-reassign */ | ||
const FUNCTION_REGEX = /tidy-(span|offset)(|-full)\(([\d.-]+)\)/; | ||
const globalRegExp = new RegExp(FUNCTION_REGEX, 'g'); | ||
const localRegExp = new RegExp(FUNCTION_REGEX); | ||
if (FUNCTION_REGEX.test(declaration.value)) { | ||
if (localRegExp.test(declaration.value)) { | ||
const { grid } = tidy; | ||
/** | ||
* match: The full function expression. | ||
* slug: One of either `span` or `offset`. | ||
* modifier: One of either `undefined` or `-full`. | ||
* value: The function's argument. | ||
*/ | ||
const [match, slug, modifier, value] = declaration.value.match(FUNCTION_REGEX); | ||
const fullMatch = declaration.value.match(globalRegExp); | ||
/** | ||
* Get the span or offset `calc()` value(s). | ||
* Find all matches in the declaration value. | ||
* | ||
* fluid: calc() function based on 100vw base. | ||
* full: calc() function based on `siteMax` base. | ||
* @param {String} acc The accumulator, based on declaration.value | ||
* @param {String} tidyMatch The full tidy function match(es) | ||
* | ||
* @return {String} The replacement value for the declaration | ||
*/ | ||
let { fluid, full } = ('span' === slug) ? | ||
grid.spanCalc(value) : | ||
grid.offsetCalc(value); | ||
const replaceWithValue = fullMatch.reduce((acc, tidyMatch) => { | ||
/** | ||
* match: The full function expression. | ||
* slug: One of either `span` or `offset`. | ||
* modifier: One of either `undefined` or `-full`. | ||
* value: The function's argument. | ||
*/ | ||
const [match, slug, modifier, value] = tidyMatch.match(localRegExp); | ||
/** | ||
* If the tidy- function is nested in a calc() function, remove 'calc' | ||
* from the span/offset values. | ||
*/ | ||
if (/^calc\(.*\)$/.test(declaration.value)) { | ||
[fluid, full] = [fluid, full].map(calc => ( | ||
(undefined !== calc) ? calc.replace('calc', '') : calc)); | ||
} | ||
/** | ||
* Get the span or offset `calc()` value(s). | ||
* | ||
* fluid: calc() function based on 100vw base. | ||
* full: calc() function based on `siteMax` base. | ||
*/ | ||
let { fluid, full } = ('span' === slug) ? | ||
grid.spanCalc(value) : | ||
grid.offsetCalc(value); | ||
acc = ('-full' === modifier) ? | ||
// tidy-[span|offset]-full() | ||
acc.replace(match, full) : | ||
// tidy-[span|offset] () | ||
acc.replace(match, fluid); | ||
/** | ||
* Remove nested calc() function resulting from the tidy-* function replacement. | ||
*/ | ||
const NESTED_CALC_REGEX = /(calc[(\s]+)(calc\()/; | ||
return (NESTED_CALC_REGEX.test(acc)) ? acc.replace(NESTED_CALC_REGEX, '$1(') : acc; | ||
}, declaration.value); | ||
// Replace declaration(s) with cloned and updated declarations. | ||
if ('-full' === modifier) { | ||
// tidy-[span|offset]-full() | ||
declaration.replaceWith(cleanClone( | ||
declaration, | ||
{ | ||
prop: declaration.prop, | ||
value: declaration.value.replace(match, full), | ||
}, | ||
)); | ||
} else { | ||
// tidy-[span|offset] () | ||
declaration.replaceWith(cleanClone( | ||
declaration, | ||
{ | ||
prop: declaration.prop, | ||
value: declaration.value.replace(match, fluid), | ||
}, | ||
)); | ||
} | ||
declaration.replaceWith(cleanClone( | ||
declaration, | ||
{ | ||
prop: declaration.prop, | ||
value: replaceWithValue, | ||
}, | ||
)); | ||
} | ||
}; |
@@ -17,3 +17,3 @@ const cleanClone = require('./utils/cleanClone'); | ||
module.exports = function tidyProperty(declaration, tidy) { | ||
const { fullWidthRule, shouldAddGapDecl, grid } = tidy; | ||
const { fullWidthRule, grid } = tidy; | ||
@@ -49,15 +49,2 @@ // Replace `tidy-span` declaration with a `width` declaration. | ||
// Conditionally insert a gap margin. | ||
if (shouldAddGapDecl) { | ||
columnDecl.push(cleanClone( | ||
declaration, | ||
{ | ||
prop: 'margin-right', | ||
value: grid.options.gap, | ||
}, | ||
)); | ||
tidy.captureDeclarationSource(declaration); | ||
} | ||
declaration.replaceWith(columnDecl); | ||
@@ -64,0 +51,0 @@ } |
@@ -58,3 +58,7 @@ const cleanClone = require('./utils/cleanClone'); | ||
// Remove slashes, spaces, and invalid/unneeded values. | ||
const values = cleanShorthandValues({ offsetLeft, span, offsetRight }); | ||
const values = cleanShorthandValues({ | ||
offsetLeft, | ||
span, | ||
offsetRight: offsetRight || offsetLeft, | ||
}); | ||
@@ -113,3 +117,6 @@ // Conditionally add the `tidy-span` property. | ||
// Remove slashes, spaces, and invalid/unneeded values. | ||
const values = cleanShorthandValues({ offsetLeft, offsetRight }); | ||
const values = cleanShorthandValues({ | ||
offsetLeft, | ||
offsetRight: offsetRight || offsetLeft, | ||
}); | ||
@@ -116,0 +123,0 @@ // Conditionally add the `tidy-offset-left` property. |
{ | ||
"name": "postcss-tidy-columns", | ||
"version": "0.4.0-beta1", | ||
"version": "0.4.0-beta2", | ||
"description": "PostCSS plugin to manage column and margin alignment.", | ||
@@ -24,7 +24,7 @@ "keywords": [ | ||
"devDependencies": { | ||
"eslint": "^4.19.1", | ||
"eslint": "^5.14.1", | ||
"eslint-config-airbnb-base": "^12.1.0", | ||
"eslint-plugin-import": "^2.12.0", | ||
"jest": "^23.0.1", | ||
"jest-cli": "^23.6.0" | ||
"jest": "^24.1.0", | ||
"jest-cli": "^24.1.0" | ||
}, | ||
@@ -31,0 +31,0 @@ "scripts": { |
@@ -96,3 +96,3 @@ # PostCSS Tidy Columns [![Build Status][ci-img]][ci] [![npm version][npmjs-img]][npmjs] | ||
Use `none` to bypass a required value. | ||
Use `none` to bypass a required value. A single offset value applies to both `left` and `right`. | ||
@@ -102,4 +102,6 @@ > #### Syntax | ||
> ``` | ||
> /* [ <number> | none ] / span && <number> [ / <number> ]? */ | ||
> [ <number> | none ] / span && <number> [ / <number> ]? | ||
> ``` | ||
> | ||
> ``` | ||
> tidy-column: 3 / span 2 / 4; | ||
@@ -114,3 +116,3 @@ > tidy-column: none / span 4 / 1; | ||
Use `none` to bypass a required value. | ||
Use `none` to bypass a required value. A single value applies to both `left` and `right`. | ||
@@ -120,7 +122,9 @@ > #### Syntax | ||
> ``` | ||
> /* [ <number> | none ] [ / <number> ]? */ | ||
> [ <number> | none ] [ / <number> ]? */ | ||
> ``` | ||
> | ||
> ``` | ||
> tidy-offset: 3 / 4; | ||
> tidy-offset: none / 1; | ||
> tidy-offset: 1; /* 1 / none */ | ||
> tidy-offset: 1; | ||
> ``` | ||
@@ -184,3 +188,2 @@ | ||
|[`edge`](#edge)|`{String}`|`undefined`|The value of the site's edge padding.| | ||
|[`addGap`](#addGap)|`{Boolean}`|`false`|Add a right `gap` margin to column declarations.| | ||
|[`breakpoints`](#breakpoints)|`{Array}`|`[]`|An array of breakpoint-specific configuration objects.| | ||
@@ -207,7 +210,5 @@ | ||
> ``` | ||
> @tidy gap <length> [ / <boolean> ]?; | ||
> @tidy gap <length>; | ||
> ``` | ||
See [`addGap`](#addgap) for more about the CSS syntax. | ||
### `siteMax` | ||
@@ -223,4 +224,6 @@ | ||
> @tidy site-max <length>; | ||
> | ||
> /* Alternatively use the camelCased JavaScript property */ | ||
> ``` | ||
> | ||
> Alternatively, use the camelCased JavaScript property. | ||
> ``` | ||
> @tidy siteMax <length>; | ||
@@ -241,37 +244,15 @@ > ``` | ||
### `addGap` | ||
Declares whether or not to add a gap-wide `margin-right` to the columns. | ||
When this is set to `true`, a `:last-of-type` rule will be added to reset the `margin-right` to `0` for the last item. | ||
> #### CSS Syntax | ||
> | ||
> ``` | ||
> /** | ||
> * Declared as a boolean value after the `gap` value. | ||
> * Must be preceeded by a slash. | ||
> */ | ||
> @tidy gap <length> / <boolean>; | ||
> ``` | ||
### `breakpoints` | ||
Use the `breakpoints` array to configure a grid spec that changes for certain breakpoints. | ||
Use the `breakpoints` array to configure a grid spec that changes across breakpoints. | ||
1. Define the small-screen grid in the root object. | ||
2. Define breakpoints at which the grid spec changes, and any configuration options that will change. | ||
2. Define `min-width` breakpoints at which the grid spec changes, and any configuration options that will change. | ||
3. The configuration settings cascade up from the root to the largest `breakpoint`. | ||
Each breakpoint configuration object must contain a `breakpoint` (singular) property defining the `min-width` breakpoint at which the configuration becomes active. There is no CSS syntax for this config option. | ||
The root configuration will cascade through the breakpoints, with each breakpoint's config overriding any changed options. Each breakpoint config will also cascade through to the next larger breakpoint config. | ||
Which means, given the following options... | ||
```js | ||
{ | ||
require('postcss-tidy-columns')({ | ||
columns: 9, | ||
edge: '1rem', | ||
gap: '0.625rem', | ||
addGap: true, | ||
breakpoints: [ | ||
@@ -286,47 +267,10 @@ { | ||
edge: '1.25rem', | ||
addGap: false, | ||
siteMax: '90rem' | ||
} | ||
] | ||
}; | ||
}); | ||
``` | ||
... each breakpoint object will essentially end up like this: | ||
See the [Scoped Settings](../../wiki/Scoped-Settings) Wiki page for more. | ||
```js | ||
{ | ||
breakpoints: [ | ||
{ // small screens | ||
columns: 9, | ||
edge: '1rem', | ||
gap: '0.625rem', | ||
addGap: true, | ||
}, | ||
{ // min-width: 48rem | ||
breakpoint: '48rem', | ||
columns: 12, | ||
gap: '1rem' | ||
edge: '1rem', | ||
addGap: true, | ||
}, | ||
{ // min-width: 64rem | ||
breakpoint: '64rem', | ||
edge: '1.25rem', | ||
addGap: false, | ||
siteMax: '90rem' | ||
columns: 12, | ||
gap: '1rem' | ||
} | ||
] | ||
}; | ||
``` | ||
**Caveats** | ||
- The `breakpoint` value must be based on a `min-width` media query. | ||
- `breakpoint` values must be in the same units as the media query it's responding to or it will be ignored and use the root config. | ||
- All `breakpoints` must also be in the same units or it will be ignored and use the root config. | ||
- A media query spanning more than one breakpoint config will be ignored and use the root config. | ||
- In the above configuration example, a media query with `(min-width: 48rem) and (max-width: 90rem)` would match two breakpoint configs and thus use the root config as a fallback. | ||
## Options Cascade | ||
@@ -352,3 +296,2 @@ | ||
1. Due to the nature of CSS Custom Properties, particularly the inability to use them in media query parmeters, a CSS Custom Property used as the `@tidy site-max` value will throw an error. | ||
2. The `@tidy gap` custom property value must only contain its length, and not its boolean `addGap` portion of the [gap shorthand](#addgap). | ||
@@ -355,0 +298,0 @@ See the [Tips and Tricks](../../wiki/Tips-and-Tricks) Wiki page for more. |
@@ -37,3 +37,2 @@ { | ||
"gap": "0.625rem", | ||
"addGap": true, | ||
"breakpoints": [ | ||
@@ -48,3 +47,2 @@ { | ||
"edge": "1.25rem", | ||
"addGap": false, | ||
"siteMax": "90rem" | ||
@@ -83,7 +81,5 @@ } | ||
{ | ||
"description": "source-maps: tidy-span (with `addGap`)", | ||
"description": "source-maps: tidy-span", | ||
"skip": false, | ||
"options": { | ||
"addGap": true | ||
}, | ||
"options": {}, | ||
"map": { | ||
@@ -95,3 +91,3 @@ "version": 3, | ||
"names": [], | ||
"mappings": "AAAA;CACC,uEAAa;CAAb,2EAAa;CAAb,sBAAa;CACb;AAFD;CACC,gBAAa;CACb", | ||
"mappings": "AAAA;CACC,uEAAa;CAAb,2EAAa;CACb", | ||
"file": "span.generated.css", | ||
@@ -98,0 +94,0 @@ "sourcesContent": [ |
14
Tidy.js
@@ -37,16 +37,2 @@ const Grid = require('./Grid'); | ||
this.fullWidthRule = cleanClone(this.rule); | ||
/** | ||
* Test the rule for whether or not gap margin declarations should be inserted. | ||
* | ||
* Conditions for adding the gap margins | ||
* - The `addGap` options is `true`. | ||
* - There is a `tidy-span` declaration in this rule. | ||
* - There is not a `tidy-offset-right` declaration in this rule. | ||
*/ | ||
const { addGap } = this.grid.options; | ||
this.shouldAddGapDecl = ( | ||
/(tidy-span:)/.test(this.rule.toString()) && | ||
!/(tidy-offset-right)/.test(this.rule.toString()) | ||
) && addGap; | ||
} | ||
@@ -53,0 +39,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
99155
1635
297