Skip to content

Commit

Permalink
[theme] Built-in convertLength method
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Feb 15, 2020
1 parent c1c6690 commit 96c9301
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable material-ui/restricted-path-imports */
import React from 'react';
import convertLength from 'convert-css-length';
import { convertLength } from '@material-ui/core/styles/cssUtils';
import { makeStyles, createMuiTheme, responsiveFontSizes } from '@material-ui/core/styles';
import {
Legend,
Expand Down
1 change: 0 additions & 1 deletion packages/material-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"@material-ui/utils": "^4.7.1",
"@types/react-transition-group": "^4.2.0",
"clsx": "^1.0.2",
"convert-css-length": "^2.0.1",
"hoist-non-react-statics": "^3.3.2",
"popper.js": "^1.14.1",
"prop-types": "^15.7.2",
Expand Down
60 changes: 60 additions & 0 deletions packages/material-ui/src/styles/cssUtils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,63 @@
export function isUnitless(value) {
return String(parseFloat(value)).length === String(value).length;
}

// Ported from Compass
// https://github.com/Compass/compass/blob/master/core/stylesheets/compass/typography/_units.scss
// Emulate the sass function "unit"
export function getUnit(input) {
return String(input).match(/[\d.\-+]*\s*(.*)/)[1] || '';
}

// Emulate the sass function "unitless"
export function toUnitless(length) {
return parseFloat(length);
}

// Convert any CSS <length> or <percentage> value to any another.
// From https://github.com/KyleAMathews/convert-css-length
export function convertLength(baseFontSize) {
return (length, toUnit) => {
const fromUnit = getUnit(length);

// Optimize for cases where `from` and `to` units are accidentally the same.
if (fromUnit === toUnit) {
return length;
}

// Convert input length to pixels.
let pxLength = toUnitless(length);

if (fromUnit !== 'px') {
if (fromUnit === 'em') {
pxLength = toUnitless(length) * toUnitless(baseFontSize);
} else if (fromUnit === 'rem') {
pxLength = toUnitless(length) * toUnitless(baseFontSize);
} else if (fromUnit === 'ex') {
pxLength = toUnitless(length) * toUnitless(baseFontSize) * 2;
} else {
return length;
}
}

// Convert length in pixels to the output unit
let outputLength = pxLength;
if (toUnit !== 'px') {
if (toUnit === 'em') {
outputLength = pxLength / toUnitless(baseFontSize);
} else if (toUnit === 'rem') {
outputLength = pxLength / toUnitless(baseFontSize);
} else if (toUnit === 'ex') {
outputLength = pxLength / toUnitless(baseFontSize) / 2;
} else {
return length;
}
}

return parseFloat(outputLength.toFixed(5)) + toUnit;
};
}

export function alignProperty({ size, grid }) {
const sizeBelow = size - (size % grid);
const sizeAbove = sizeBelow + grid;
Expand Down
56 changes: 49 additions & 7 deletions packages/material-ui/src/styles/cssUtils.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,49 @@
import { assert } from 'chai';
import { alignProperty, fontGrid, responsiveProperty } from './cssUtils';
import { expect } from 'chai';
import {
isUnitless,
getUnit,
toUnitless,
convertLength,
alignProperty,
fontGrid,
responsiveProperty,
} from './cssUtils';

describe('cssUtils', () => {
describe('isUnitless', () => {
it('should work as expected', () => {
expect(isUnitless('20px')).to.equal(false);
expect(isUnitless('2.5 px')).to.equal(false);
expect(isUnitless('2.5 %')).to.equal(false);
expect(isUnitless('-2.5')).to.equal(true);
});
});

describe('getUnit', () => {
it('should work as expected', () => {
expect(getUnit('20px')).to.equal('px');
expect(getUnit('2.5 px')).to.equal('px');
expect(getUnit('2.5 %')).to.equal('%');
expect(getUnit('-2.5')).to.equal('');
});
});

describe('toUnitless', () => {
it('should work as expected', () => {
expect(toUnitless('20px')).to.equal(20);
expect(toUnitless('2.5 px')).to.equal(2.5);
expect(toUnitless('2.5 %')).to.equal(2.5);
expect(toUnitless('-2.5')).to.equal(-2.5);
});
});

describe('convertLength', () => {
it('should work as expected', () => {
const convert = convertLength('16px');
expect(convert('32px', 'rem')).to.equal('2rem');
});
});

describe('alignProperty', () => {
const tests = [
{ args: { size: 8, grid: 4 }, expected: 8 },
Expand All @@ -19,7 +61,7 @@ describe('cssUtils', () => {

it(`aligns ${size} on grid ${grid} to ${expected}`, () => {
const sizeAligned = alignProperty({ size, grid });
assert.strictEqual(sizeAligned, expected);
expect(sizeAligned).to.equal(expected);
});
});
});
Expand All @@ -40,7 +82,7 @@ describe('cssUtils', () => {

it(`should return a font grid such that the relative lineHeight is aligned`, () => {
const absoluteLineHeight = grid * lineHeight * htmlFontSize;
assert.strictEqual(Math.round((absoluteLineHeight % pixels) * 100000) / 100000, 0);
expect(Math.round((absoluteLineHeight % pixels) * 100000) / 100000).to.equal(0);
});
});

Expand All @@ -49,7 +91,7 @@ describe('cssUtils', () => {
there is no smaller font aligning the lineHeight`, () => {
const grid = fontGrid({ lineHeight, pixels, htmlFontSize });
const absoluteLineHeight = grid * lineHeight * htmlFontSize;
assert.strictEqual(Math.floor(absoluteLineHeight / pixels), 1);
expect(Math.floor(absoluteLineHeight / pixels)).to.equal(1);
});
});
});
Expand All @@ -65,7 +107,7 @@ describe('cssUtils', () => {
breakpoints: [300, 600],
});

assert.deepEqual(result, {
expect(result).to.deep.equal({
fontSize: '15px',
'@media (min-width:300px)': {
fontSize: '17.5px',
Expand All @@ -87,7 +129,7 @@ describe('cssUtils', () => {
breakpoints: [500],
});

assert.deepEqual(result, {
expect(result).to.deep.equal({
fontSize: '0.875rem',
'@media (min-width:500px)': {
fontSize: '1rem',
Expand Down
7 changes: 1 addition & 6 deletions packages/material-ui/src/styles/responsiveFontSizes.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import convertLength from 'convert-css-length';
import { responsiveProperty, alignProperty, fontGrid } from './cssUtils';

function isUnitless(value) {
return String(parseFloat(value)).length === String(value).length;
}
import { isUnitless, convertLength, responsiveProperty, alignProperty, fontGrid } from './cssUtils';

export default function responsiveFontSizes(themeInput, options = {}) {
const {
Expand Down
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4845,11 +4845,6 @@ conventional-recommended-bump@^5.0.0:
meow "^4.0.0"
q "^1.5.1"

convert-css-length@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/convert-css-length/-/convert-css-length-2.0.1.tgz#90a76bde5bfd24d72881a5b45d02249b2c1d257c"
integrity sha512-iGpbcvhLPRKUbBc0Quxx7w/bV14AC3ItuBEGMahA5WTYqB8lq9jH0kTXFheCBASsYnqeMFZhiTruNxr1N59Axg==

convert-source-map@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
Expand Down

0 comments on commit 96c9301

Please sign in to comment.