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@intracto.com>2018-12-31 14:50:11 +0300
committerMartijn Cuppens <martijn.cuppens@gmail.com>2019-02-11 21:27:14 +0300
commit62a772a9c63b42b0df0418b9e58546673aff8e96 (patch)
tree4b1ce72e33aa3900357784db127230fd43c8d33f /postcss.js
parent6628f33db3b46ebf651be88b7e12fccf2d97ed53 (diff)
Move files to root to make imports easier
Diffstat (limited to 'postcss.js')
-rw-r--r--postcss.js212
1 files changed, 212 insertions, 0 deletions
diff --git a/postcss.js b/postcss.js
new file mode 100644
index 0000000..7263b93
--- /dev/null
+++ b/postcss.js
@@ -0,0 +1,212 @@
+// PostCSS RFS plugin
+//
+// Automated font-resizing
+//
+// See https://github.com/twbs/rfs
+
+'use strict';
+
+const postcss = require('postcss');
+
+module.exports = postcss.plugin('postcss-rfs', function (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
+ };
+ 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);
+ }
+ }
+
+ return function (css) {
+
+ css.walkRules(function (rule) {
+
+ if (rule.selector.includes(DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR)) {
+ return;
+ }
+
+ rule.walkDecls(function (decl) {
+ // Skip if property is not in propList
+ if (opts.propList.indexOf(decl.prop) === -1) {
+ return;
+ }
+
+ // 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.indexOf('rem') > -1) {
+ 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`.');
+ }
+
+ // Only add media query if needed
+ if (opts.baseFontSize >= value || opts.factor <= 1 || !opts.enableResponsiveFontSizes) {
+ return;
+ }
+
+ // Calculate font-size and font-size difference
+ let baseFontSize = opts.baseFontSize + (value - opts.baseFontSize) / opts.factor;
+ const fontSizeDiff = value - baseFontSize;
+
+ // Divide by remValue if needed
+ if (opts.fontSizeUnit === 'rem') {
+ baseFontSize /= opts.remValue;
+ }
+
+ 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 rule_selector = rule.selector;
+
+ // Prefix with .enable-responsive-font-size class if needed
+ if (opts.class === 'enable') {
+ const selectors = rule.selector.split(',');
+ let ruleSelector = '';
+
+ for (let selector of selectors) {
+ ruleSelector += ENABLE_RESPONSIVE_FONT_SIZE_SELECTOR + ' ' + selector + ',\n';
+ ruleSelector += selector + ENABLE_RESPONSIVE_FONT_SIZE_SELECTOR + ',\n';
+ }
+ rule_selector = ruleSelector.slice(0, -2);
+ }
+
+
+ const mediaQueryRule = postcss.rule({
+ selector: rule_selector,
+ source: rule.source
+ });
+ mediaQueryRule.append(decl.clone({value: value}));
+
+ // Safari iframe resize bug: https://github.com/twbs/rfs/issues/14
+ if (opts.safariIframeResizeBugFix) {
+ mediaQueryRule.append(postcss.decl({ prop: 'min-width', value: '0vw' }));
+ }
+
+ mediaQuery.append(mediaQueryRule);
+ rule.parent.insertAfter(rule, mediaQuery.clone());
+
+ // Disable classes
+ if (opts.class === 'disable') {
+ const selectors = rule.selector.split(',');
+ let ruleSelector = '';
+
+ for (let selector of selectors) {
+ ruleSelector += selector + ',\n';
+ ruleSelector += DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR + ' ' + selector + ',\n';
+ ruleSelector += selector + DISABLE_RESPONSIVE_FONT_SIZE_SELECTOR + ',\n';
+ }
+ ruleSelector = ruleSelector.slice(0, - 2);
+
+ const dc_rule = postcss.rule({
+ selector: ruleSelector,
+ source: rule.source
+ });
+
+ dc_rule.append(decl.clone());
+ rule.parent.insertAfter(rule, dc_rule);
+ decl.prev() || decl.next() ? decl.remove() : 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 + ')';
+ }
+ 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),
+ wholeNumber = Math.floor(number * multiplier);
+ return Math.round(wholeNumber / 10) * 10 / multiplier;
+ }
+});