Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/rfs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartijn Cuppens <martijn.cuppens@gmail.com>2019-08-28 19:05:56 +0300
committerGitHub <noreply@github.com>2019-08-28 19:05:56 +0300
commit89f7a63ee4826b646ec659709cc170b8c45cddbc (patch)
treeaab7f3991699ffe9f423a0599b9e1c75442e6d4d /postcss.js
parent7a15c1a4e41b1fd46b3f26be3529abc1e2d65a4d (diff)
Support for every property (#144)
- Support for all properties - Shorthand mixins for margins and paddings - Support for custom properties - Clearer way to declare `!important` rules: `@include rfs(1rem !important)` instead of `@include rfs(1rem, true)` - Switched to mobile first approach, still possible to switch to the `max-width` media queries if needed - Configuration variables are changed: - Base font size -> Base value - Font size unit -> Unit - `responsive-font-size` property changed to `rfs()` function (see https://github.com/twbs/rfs/issues/116) - Dropped `responsive-font-size` mixins - Dropped Less 2 support since we had to work with lists - Prevent generation of `/test/expected/main.css` - Additional tests for new implementations - Cleanup npm scripts examples - Code examples in `README.md` are grouped by processor and collapsed
Diffstat (limited to 'postcss.js')
-rw-r--r--postcss.js275
1 files changed, 100 insertions, 175 deletions
diff --git a/postcss.js b/postcss.js
index 4980683..867afe2 100644
--- a/postcss.js
+++ b/postcss.js
@@ -1,7 +1,7 @@
/*!
* PostCSS RFS plugin
*
- * Automated font-resizing
+ * Automated responsive values for for font sizes, paddings, margins and much more
*
* Licensed under MIT (https://github.com/twbs/rfs/blob/master/LICENSE)
*/
@@ -9,211 +9,136 @@
'use strict';
const postcss = require('postcss');
+const RfsClass = require('./lib/rfs.js');
+
+const DISABLE_RFS_SELECTOR = '.disable-rfs';
+const ENABLE_RFS_SELECTOR = '.enable-rfs';
module.exports = postcss.plugin('postcss-rfs', opts => {
- const BREAKPOINT_ERROR = 'breakpoint option is invalid, it must be set in `px`, `rem` or `em`.';
- const BREAKPOINT_UNIT_ERROR = 'breakpointUnit option is invalid, it must be `px`, `rem` or `em`.';
- const BASE_FONT_SIZE_ERROR = 'baseFontSize option is invalid, it must be set in `px` or `rem`.';
- const DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR = '.disable-responsive-font-size';
- const ENABLE_RESPONSIVE_FONT_SIZE_SELECTOR = '.enable-responsive-font-size';
-
- const defaultOptions = {
- baseFontSize: 20,
- fontSizeUnit: 'rem',
- breakpoint: '75rem',
- breakpointUnit: 'px',
- factor: 10,
- twoDimensional: false,
- unitPrecision: 5,
- remValue: 16,
- propList: ['responsive-font-size', 'rfs'],
- class: false,
- safariIframeResizeBugFix: false,
- enableResponsiveFontSizes: true
- };
+ const rfs = new RfsClass(opts);
- opts = Object.assign(defaultOptions, opts);
-
- if (typeof opts.baseFontSize !== 'number') {
- if (opts.baseFontSize.endsWith('px')) {
- opts.baseFontSize = parseFloat(opts.baseFontSize);
- } else if (opts.baseFontSize.endsWith('rem')) {
- opts.baseFontSize = parseFloat(opts.baseFontSize) / opts.remValue;
- } else {
- console.error(BASE_FONT_SIZE_ERROR);
- }
- }
-
- if (typeof opts.breakpoint !== 'number') {
- if (opts.breakpoint.endsWith('px')) {
- opts.breakpoint = parseFloat(opts.breakpoint);
- } else if (opts.breakpoint.endsWith('em')) {
- opts.breakpoint = parseFloat(opts.breakpoint) * opts.remValue;
- } else {
- console.error(BREAKPOINT_ERROR);
- }
- }
+ // Get the options merged with defaults
+ opts = rfs.getOptions();
+ const mediaQuery = rfs.renderMediaQuery();
return css => {
css.walkRules(rule => {
- if (rule.selector.includes(DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR)) {
- return;
- }
-
- rule.walkDecls(decl => {
- // Skip if property is not in propList
- if (!opts.propList.includes(decl.prop)) {
- return;
+ const mediaQueryRules = [];
+ const extraBlocks = [];
+ const {parent} = rule;
+ let removeRule = false;
+ let dcRule;
+ let ecRule;
+ let ruleSelector = rule.selector;
+
+ // Prepare rule to add to media query
+ if (opts.class === 'enable') {
+ const selectors = rule.selector.split(',');
+ let tempRuleSelector = '';
+
+ for (const selector of selectors) {
+ tempRuleSelector += `${ENABLE_RFS_SELECTOR} ${selector},\n`;
+ tempRuleSelector += `${selector + ENABLE_RFS_SELECTOR},\n`;
}
- // Set property to font-size
- decl.prop = 'font-size';
-
- // Skip if value is not in px or rem
- if (isNaN(decl.value) && !new RegExp(/(\d*\.?\d+)(px|rem)/g).test(decl.value)) {
- return;
- }
-
- // Get the float value of the value
- let value = parseFloat(decl.value);
-
- // Multiply by remValue if value is in rem
- if (decl.value.includes('rem')) {
- value *= opts.remValue;
- }
-
- // Render value in desired unit
- if (opts.fontSizeUnit === 'px') {
- decl.value = `${toFixed(value, opts.unitPrecision)}px`;
- } else if (opts.fontSizeUnit === 'rem') {
- decl.value = `${toFixed(value / opts.remValue, opts.unitPrecision)}rem`;
- } else {
- console.error('fontSizeUnit option is not valid, it must be `px` or `rem`.');
- }
+ ruleSelector = tempRuleSelector.slice(0, -2);
+ }
- // Only add media query if needed
- if (opts.baseFontSize >= value || opts.factor <= 1 || !opts.enableResponsiveFontSizes) {
- return;
- }
+ const fluidRule = postcss.rule({
+ selector: ruleSelector
+ });
- // Calculate font-size and font-size difference
- let baseFontSize = opts.baseFontSize + ((value - opts.baseFontSize) / opts.factor);
- const fontSizeDiff = value - baseFontSize;
+ // Disable classes
+ if (opts.class === 'disable') {
+ const selectors = rule.selector.split(',');
+ let ruleSelector = '';
- // Divide by remValue if needed
- if (opts.fontSizeUnit === 'rem') {
- baseFontSize /= opts.remValue;
+ for (const selector of selectors) {
+ ruleSelector += (opts.mode === 'max-media-query') ? `${selector},\n` : '';
+ ruleSelector += `${DISABLE_RFS_SELECTOR} ${selector},\n`;
+ ruleSelector += `${selector + DISABLE_RFS_SELECTOR},\n`;
}
- const viewportUnit = opts.twoDimensional ? 'vmin' : 'vw';
-
- value = `calc(${toFixed(baseFontSize, opts.unitPrecision)}${opts.fontSizeUnit} + ${toFixed(fontSizeDiff * 100 / opts.breakpoint, opts.unitPrecision)}${viewportUnit})`;
-
- const mediaQuery = postcss.atRule(renderMediaQuery(opts));
- let ruleSelector = rule.selector;
-
- // Prefix with .enable-responsive-font-size class if needed
- if (opts.class === 'enable') {
- const selectors = rule.selector.split(',');
- let tempRuleSelector = '';
-
- for (const selector of selectors) {
- tempRuleSelector += `${ENABLE_RESPONSIVE_FONT_SIZE_SELECTOR} ${selector},\n`;
- tempRuleSelector += `${selector + ENABLE_RESPONSIVE_FONT_SIZE_SELECTOR},\n`;
- }
-
- ruleSelector = tempRuleSelector.slice(0, -2);
- }
+ ruleSelector = ruleSelector.slice(0, -2);
- const mediaQueryRule = postcss.rule({
+ dcRule = postcss.rule({
selector: ruleSelector,
source: rule.source
});
+ }
- mediaQueryRule.append(decl.clone({value}));
+ rule.walkDecls(decl => {
+ // Check if the selector doesn't contain the disabled selector
+ // Check if value contains rfs() function
+ if (!rule.selector.includes(DISABLE_RFS_SELECTOR) && new RegExp(opts.functionName + '(.*)', 'g').test(decl.value)) {
+ const value = rfs.value(decl.value);
+ const fluidValue = rfs.fluidValue(decl.value);
+ decl.value = value;
+
+ if (value !== fluidValue) {
+ const defaultValue = (opts.mode === 'min-media-query') ? ((opts.class === 'enable') ? value : fluidValue) : value;
+ const mediaQueryValue = (opts.mode === 'min-media-query') ? value : fluidValue;
+ decl.value = defaultValue;
+
+ fluidRule.append(decl.clone({value: mediaQueryValue}));
+ mediaQueryRules.push(fluidRule);
+
+ // Disable classes
+ if (opts.class === 'disable') {
+ const declOpts = (opts.mode === 'max-media-query') ? {} : {value};
+ dcRule.append(decl.clone(declOpts));
+ extraBlocks.push(dcRule);
+ } else if (opts.class === 'enable' && opts.mode === 'min-media-query') {
+ if (ecRule === undefined) {
+ ecRule = postcss.rule({
+ selector: ruleSelector,
+ source: parent.source
+ });
+ }
+
+ ecRule.append(decl.clone({value: fluidValue}));
+ extraBlocks.push(ecRule);
+ }
+
+ // Remove declaration if needed
+ if (opts.class === 'disable' && opts.mode === 'max-media-query') {
+ if (decl.prev() || decl.next()) {
+ decl.remove();
+ } else {
+ removeRule = true;
+ }
+ }
+ }
+ }
+ });
+ if (mediaQueryRules.length !== 0) {
// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14
if (opts.safariIframeResizeBugFix) {
- mediaQueryRule.append(postcss.decl({
+ rule.append({
prop: 'min-width',
value: '0vw'
- }));
+ });
}
- mediaQuery.append(mediaQueryRule);
- rule.parent.insertAfter(rule, mediaQuery.clone());
+ const fluidMediaQuery = mediaQuery.clone();
- // Disable classes
- if (opts.class === 'disable') {
- const selectors = rule.selector.split(',');
- let ruleSelector = '';
-
- for (const selector of selectors) {
- ruleSelector += `${selector},\n`;
- ruleSelector += `${DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR} ${selector},\n`;
- ruleSelector += `${selector + DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR},\n`;
- }
+ mediaQueryRules.forEach(mediaQueryRule => {
+ fluidMediaQuery.append(mediaQueryRule);
+ });
- ruleSelector = ruleSelector.slice(0, -2);
+ parent.insertAfter(rule, fluidMediaQuery);
- const dcRule = postcss.rule({
- selector: ruleSelector,
- source: rule.source
+ if (extraBlocks.length > 0) {
+ extraBlocks.forEach(disableBlock => {
+ parent.insertAfter(rule, disableBlock);
});
-
- dcRule.append(decl.clone());
- rule.parent.insertAfter(rule, dcRule);
-
- if (decl.prev() || decl.next()) {
- decl.remove();
- } else {
- decl.parent.remove();
- }
}
- });
- });
- };
- function renderMediaQuery(opts) {
- const mediaQuery = {
- name: 'media'
- };
-
- switch (opts.breakpointUnit) {
- case 'em':
- case 'rem': {
- const breakpoint = opts.breakpoint / opts.remValue;
-
- if (opts.twoDimensional) {
- mediaQuery.params = `(max-width: ${breakpoint}${opts.breakpointUnit}), (max-height: ${breakpoint}${opts.breakpointUnit})`;
- } else {
- mediaQuery.params = `(max-width: ${breakpoint}${opts.breakpointUnit})`;
+ if (removeRule) {
+ rule.remove();
}
-
- break;
}
-
- case 'px':
- if (opts.twoDimensional) {
- mediaQuery.params = `(max-width: ${opts.breakpoint}px), (max-height: ${opts.breakpoint}px)`;
- } else {
- mediaQuery.params = `(max-width: ${opts.breakpoint}px)`;
- }
-
- break;
-
- default:
- console.error(BREAKPOINT_UNIT_ERROR);
- break;
- }
-
- return mediaQuery;
- }
-
- function toFixed(number, precision) {
- const multiplier = Math.pow(10, precision + 1);
- const wholeNumber = Math.floor(number * multiplier);
-
- return Math.round(wholeNumber / 10) * 10 / multiplier;
- }
+ });
+ };
});