Skip to content

Commit 95c16b8

Browse files
committed
feat(core utils): add parseLength method for parsing px and % lengths.
1 parent 52d9ecf commit 95c16b8

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed

src/core/utils.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,54 @@ function parseTime(time) {
442442
}
443443
}
444444

445+
/*
446+
447+
* parseLength - Parse a length from a string and return the parsed length in
448+
* pixels.
449+
450+
* @param {String} length - A length string like `1px` or `25%`.
451+
* @param {Number} reference_length - The reference length to use for percentage lengths.
452+
*
453+
* @returns {Number} - A integer which represents the parsed length in pixels.
454+
*
455+
* @throws {Error} - If the length string is invalid.
456+
*
457+
* @example
458+
* parseLength("1px"); // 1
459+
* parseLength("10%", 100); // 10
460+
*
461+
*/
462+
function parseLength(length, reference_length = null) {
463+
const m = /^(\d+(?:\.\d+)?)\s*(\%?\w*)/.exec(length);
464+
if (!m) {
465+
throw new Error("Invalid length");
466+
}
467+
const amount = parseFloat(m[1]);
468+
switch (m[2]) {
469+
case "px":
470+
return Math.round(amount);
471+
case "%":
472+
if (!reference_length) {
473+
return 0;
474+
}
475+
return (reference_length / 100) * Math.round(amount);
476+
case "vw":
477+
return Math.round((amount * window.innerWidth) / 100);
478+
case "vh":
479+
return Math.round((amount * window.innerHeight) / 100);
480+
case "vmin":
481+
return Math.round(
482+
(amount * Math.min(window.innerWidth, window.innerHeight)) / 100
483+
);
484+
case "vmax":
485+
return Math.round(
486+
(amount * Math.max(window.innerWidth, window.innerHeight)) / 100
487+
);
488+
default:
489+
return null;
490+
}
491+
}
492+
445493
// Return a jQuery object with elements related to an input element.
446494
function findRelatives(el) {
447495
var $el = $(el),
@@ -723,6 +771,7 @@ var utils = {
723771
isElementInViewport: isElementInViewport,
724772
hasValue: hasValue,
725773
parseTime: parseTime,
774+
parseLength: parseLength,
726775
findRelatives: findRelatives,
727776
get_bounds: get_bounds,
728777
checkInputSupport: checkInputSupport,

src/core/utils.test.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,76 @@ describe("parseTime", function () {
472472
});
473473
});
474474

475+
describe("parseLength", function () {
476+
it("raises exception for invalid input", function () {
477+
var p = function () {
478+
utils.parseLength("abc");
479+
};
480+
expect(p).toThrow();
481+
});
482+
483+
it("handles pixel lengths", function () {
484+
expect(utils.parseLength("10px")).toBe(10);
485+
expect(utils.parseLength("100px")).toBe(100);
486+
expect(utils.parseLength("1000.1px")).toBe(1000);
487+
expect(utils.parseLength("1000.9px")).toBe(1001);
488+
489+
expect(utils.parseLength("10 px")).toBe(10);
490+
});
491+
492+
it("handles percent lengths", function () {
493+
expect(utils.parseLength("10%", 1)).toBe(0.1);
494+
expect(utils.parseLength("10%", 10)).toBe(1);
495+
expect(utils.parseLength("10%", 100)).toBe(10);
496+
expect(utils.parseLength("10%", 1000)).toBe(100);
497+
498+
expect(utils.parseLength("10.1%", 100)).toBe(10);
499+
expect(utils.parseLength("10.9%", 100)).toBe(11);
500+
501+
expect(utils.parseLength("10 %", 100)).toBe(10);
502+
});
503+
504+
it("handles vw lengths", function () {
505+
jest.replaceProperty(window, "innerWidth", 1000);
506+
507+
expect(utils.parseLength("1vw")).toBe(10);
508+
expect(utils.parseLength("10vw")).toBe(100);
509+
expect(utils.parseLength("100vw")).toBe(1000);
510+
511+
expect(utils.parseLength("10 vw")).toBe(100);
512+
});
513+
514+
it("handles vh lengths", function () {
515+
jest.replaceProperty(window, "innerHeight", 1000);
516+
517+
expect(utils.parseLength("1vh")).toBe(10);
518+
expect(utils.parseLength("10vh")).toBe(100);
519+
expect(utils.parseLength("100vh")).toBe(1000);
520+
521+
expect(utils.parseLength("10 vh")).toBe(100);
522+
});
523+
524+
it("handles vmin lengths", function () {
525+
jest.replaceProperty(window, "innerHeight", 100);
526+
jest.replaceProperty(window, "innerWidth", 200);
527+
expect(utils.parseLength("10vmin")).toBe(10);
528+
529+
jest.replaceProperty(window, "innerHeight", 100);
530+
jest.replaceProperty(window, "innerWidth", 50);
531+
expect(utils.parseLength("10vmin")).toBe(5);
532+
});
533+
534+
it("handles vmax lengths", function () {
535+
jest.replaceProperty(window, "innerHeight", 100);
536+
jest.replaceProperty(window, "innerWidth", 200);
537+
expect(utils.parseLength("10vmax")).toBe(20);
538+
539+
jest.replaceProperty(window, "innerHeight", 100);
540+
jest.replaceProperty(window, "innerWidth", 50);
541+
expect(utils.parseLength("10vmax")).toBe(10);
542+
});
543+
});
544+
475545
describe("get_bounds", function () {
476546
it("returns the bounds values as integer numbers instead of double/float values.", () => {
477547
const el = document.createElement("div");

0 commit comments

Comments
 (0)