UNPKG

backpack-ui

Version:

Lonely Planet's Components

267 lines (224 loc) 6.93 kB
"use strict"; const settings = { columns: 12, columnWidth: 80, container: 1290, gutterPosition: "before", gutters: (3 / 8), math: "fluid", output: "float", staticUnit: "px", remBase: 10, }; function _calculateGutter(multiplier = 1) { return (settings.columnWidth * settings.gutters * multiplier); } function _rem(value, base) { return `${(value / base)}rem`; } function _px(value) { return `${value}px`; } function _percent(target, context) { return `${(target / context) * 100}%`; } function _staticCalculation(value) { if (settings.staticUnit && settings.staticUnit === "rem" && settings.remBase) { return _rem(value, settings.remBase); } return _px(value); } function _updateContext(columns) { const contextWidth = (columns * settings.columnWidth); const contextGutters = (columns - 1); const gutterWidth = _calculateGutter(); return (contextWidth + (contextGutters * gutterWidth)); } function _affixValue(number, math) { if (math === "fluid") { return `${number}%`; } if (math === "static") { if (settings.staticUnit === "rem") { return `${number}rem`; } return `${number}px`; } return false; } function _getNumbers([...values], math = settings.math, unit = settings.staticUnit) { const numbers = []; values.map((value) => { if (math === "fluid") { numbers.push(parseFloat(value.slice(0, -1))); } if (math === "static") { if (unit === "rem") { numbers.push(parseFloat(value.slice(0, -3))); } else { numbers.push(parseFloat(value.slice(0, -2))); } } return false; }); return numbers; } /** * Add values together * @todo protect against mix of static and fluid values * @param {array} [...values] Array of values to add * @param {string} math Type of calculation, "fluid" or "static"; * * @return {string} Calculation converted back to a string with * the correct units based on `math` * @usage * add([span("2 of 6"), gutter()]); // fluid * add([span(3, "static"), gutter("static")], "static"); // static */ function add([...values], math = settings.math) { const numbers = _getNumbers(values, math); const result = numbers.reduce((a, b) => a + b); return _affixValue(result, math); } function subtract([...values], math = settings.math) { const numbers = _getNumbers(values, math); const result = numbers.reduce((a, b) => a - b); return _affixValue(result, math); } function multiply([...values], math = settings.math) { const numbers = _getNumbers(values, math); const result = numbers.reduce((a, b) => a * b); return _affixValue(result, math); } function divide([...values], math = settings.math) { const numbers = _getNumbers(values, math); const result = numbers.reduce((a, b) => a / b); return _affixValue(result, math); } /** * Calculate a percent value from two static values * @todo Add better regex matching to validate rem or px only * @param {String} target The width of the element that will be converted to a percent * @param {String} context The width of the element's container * @return {String} Converted value * @usage * percentage("12rem", "120rem"); */ function percentage(target, context) { if (target.slice(-1) === "%" || context.slice(-1) === "%") { throw new Error(`Cannot calculate percentage; one or more units appear to be %. Units must be rem or px.`); } if (target.slice(-1) !== context.slice(-1)) { throw new Error("Cannot calculate percentage; units do not appear to match."); } const unit = target.slice(-1) === "x" ? "px" : "rem"; const numbers = _getNumbers([target, context], "static", unit); const result = numbers.reduce((a, b) => a / b) * 100; return _affixValue(result, "fluid"); } /** * Output the container width * @return {function} Function to make calculation */ function container() { return _staticCalculation(settings.container); } /** * Output the gutter width * @param {string} math Type of calculation, "fluid" or "static"; * defaults to global settings * @param {number} columns The number of columns; changes context * @param {number} multiplier Number to multiply the gutter by * @return {function} Function to make calculation */ function gutter( math = settings.math, columns = settings.columns, multiplier = 1 ) { const gutterWidth = _calculateGutter(multiplier); const containerWidth = _updateContext( typeof columns === "string" ? parseInt(columns, 10) : columns ); if (math === "static") { return _staticCalculation(gutterWidth); } if (math === "fluid") { return _percent(gutterWidth, containerWidth); } return false; } /** * Calculate a span width * @param {number|string} columns The number of columns; pass in an * optional context * @param {string} math Type of calculation, "fluid" or "static"; * defaults to global settings * @return {function} Function to make calculation * * @usage * // number, context is taken from global settings * span(2); * * // string, context is taken from global settings, math overrides global settings * span("2", "static"); * * // string with new context, calculates based on a 6 column grid * span("2 of 6"); */ function span(columns, math = settings.math) { const error = "You must pass a number greater than 0 for the number of columns."; let spanColumns = 0; let containerColumns = settings.columns; if (typeof columns === "string") { spanColumns = parseInt(columns.split(" of ")[0], 10); if (columns.split(" of ")[1]) { containerColumns = parseInt(columns.split(" of ")[1], 10); } } else if (typeof columns === "number" && columns) { spanColumns = columns; } else { throw new Error(error); } if (columns) { let columnWidth = spanColumns * settings.columnWidth; const gutters = (spanColumns - 1); const containerWidth = _updateContext(containerColumns); if (settings.gutterPosition === "before" || settings.gutterPosition === "after" || settings.gutterPosition === "split") { if (gutters) { columnWidth += (_calculateGutter() * gutters); } } if (settings.gutterPosition === "inside" || settings.gutterPosition === "inside-static") { if (gutters) { columnWidth += (_calculateGutter()) * 2; } else { columnWidth += (_calculateGutter()); } } if (math === "static") { return _staticCalculation(columnWidth); } if (math === "fluid") { return _percent(columnWidth, containerWidth); } return false; } return false; } export { container, gutter, span, add, subtract, multiply, divide, percentage, };