diff --git a/generator.js b/generator.js index 9f45edc..6a37ca4 100755 --- a/generator.js +++ b/generator.js @@ -2,6 +2,7 @@ TODO: write tests (lazy) like always right? <3 */ const parser = require("gradient-parser"); +const memoize = require("fast-memoize"); const getColor = color => { switch (color.type) { @@ -14,27 +15,23 @@ const getColor = color => { } }; -const getColorsAndLocations = (colorStops, maxWidth) => +const getColorsAndLocations = memoize((colorStops, maxWidth) => colorStops.reduce( (acc, color, index) => { acc.colors = [...acc.colors, getColor(color)]; // PX value for location will break! // TODO Make it happen for px + repeat? - const locationValue = getPixelsForColor( - color, - colorStops.length, - index, - maxWidth - ); + const locationValue = getPixelsForColor(color, colorStops.length, index, maxWidth); acc["locations"] = [...acc.locations, locationValue]; return acc; }, { colors: [], locations: [] } - ); + ) +); -const getPixelsForColor = (color, colorsLength, index, maxWidth) => { +const getPixelsForColor = memoize((color, colorsLength, index, maxWidth) => { const { length } = color; if (!length) { return (1 / (colorsLength - 1)) * index; @@ -49,33 +46,30 @@ const getPixelsForColor = (color, colorsLength, index, maxWidth) => { return length.value / 100; } } -}; +}); + const getRepeatingColorsAndLocations = (colorStops, sizes) => { const { width: maxWidth, height: maxHeight } = sizes; - - if (!maxWidth && !maxHeight) { - throw new Error( - "You have to define width and height for repeating gradient to work" - ); - } - - const { - colors: initialColors, - locations: initialLocations - } = getColorsAndLocations(colorStops, maxWidth); + const { colors: initialColors, locations: initialLocations } = getColorsAndLocations(colorStops, maxWidth); const maxValue = parseFloat(initialLocations.slice(-1)[0]); const increment = maxValue / maxWidth; - const maxChunks = Math.round(maxWidth / maxValue) + 1; + // we need to add +1 but this is breaking LinearGradient, maybe can't render + // it outside the viewport. + const maxChunks = Math.round(maxWidth / maxValue); const locations = [...Array(maxChunks).keys()].reduce((acc, i) => { - return [...acc, ...initialLocations.map(j => j / maxWidth + increment * i)]; + return [ + ...acc, + ...initialLocations.map(j => { + return j / maxWidth + increment * i; + }) + ]; }, []); - const colors = locations.map( - (_, i) => initialColors[i % initialColors.length] - ); + const colors = locations.map((_, i) => initialColors[i % initialColors.length]); - return { locations, colors }; + return { colors, locations }; }; -const getVectorsByDirection = direction => { + +const getVectorsByDirection = memoize(direction => { switch (direction) { case "top": return getVectorsByAngle(0); @@ -94,27 +88,31 @@ const getVectorsByDirection = direction => { case "right bottom": return getVectorsByAngle(90 + 45); } -}; -const round = number => Math.round(number * 1000) / 1000; -const degreesToRadians = function(degrees) { - return (degrees * Math.PI) / 180; -}; -const getVectorsByAngle = alfa => { +}); + +const round = memoize(number => Math.round(number * 10000) / 10000); +const degreesToRadians = memoize(degrees => (degrees * Math.PI) / 180); + +const getVectorsByAngle = memoize(alfa => { const angle = degreesToRadians(alfa); - let gradientLineLength = round( - Math.abs(Math.sin(angle)) + Math.abs(Math.cos(angle)) - ); + let gradientLineLength = round(Math.abs(Math.sin(angle)) + Math.abs(Math.cos(angle))); let center = { x: 0.5, y: 0.5 }; let yDiff = (Math.sin(angle - Math.PI / 2) * gradientLineLength) / 2; let xDiff = (Math.cos(angle - Math.PI / 2) * gradientLineLength) / 2; return { - start: [center.x - xDiff, center.y - yDiff], - end: [center.x + xDiff, center.y + yDiff] + start: { + x: center.x - xDiff, + y: center.y - yDiff + }, + end: { + x: center.x + xDiff, + y: center.y + yDiff + } }; -}; +}); const getVectorsByOrientation = orientation => { return orientation.type === "directional" @@ -122,7 +120,7 @@ const getVectorsByOrientation = orientation => { : getVectorsByAngle(orientation.value); }; -const generateGradient = (gradient, sizes) => { +const generateGradient = memoize((gradient, sizes) => { return parser.parse(gradient).map(({ type, colorStops, orientation }) => { // YOLO: Radial gradients <3 if (type === "radial-gradient") { @@ -138,6 +136,6 @@ const generateGradient = (gradient, sizes) => { ...getVectorsByOrientation(orientation) }; }); -}; +}); export default generateGradient; diff --git a/index.js b/index.js index 8186851..26835af 100755 --- a/index.js +++ b/index.js @@ -1,11 +1,15 @@ import React from "react"; import { View, StyleSheet } from "react-native"; import generateGradient from "./generator"; -import { LinearGradient } from "expo-linear-gradient"; export { generateGradient }; export default ({ gradient, children, style }) => { + // Avoid breaking this when people are not using expo :) + // find a better solution to expose either expo-linear-gradient or + // react-native-linear-gradient. + const { LinearGradient } = require("expo-linear-gradient"); + const generated = generateGradient(gradient, { width: style.width, height: style.height @@ -20,6 +24,7 @@ export default ({ gradient, children, style }) => { ); } + return ( {children || null} diff --git a/package-lock.json b/package-lock.json index 4233d02..5f066f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,14 @@ { "name": "react-native-css-gradient", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { + "fast-memoize": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.1.tgz", + "integrity": "sha512-xdmw296PCL01tMOXx9mdJSmWY29jQgxyuZdq0rEHMu+Tpe1eOEtCycoG6chzlcrWsNgpZP7oL8RiQr7+G6Bl6g==" + }, "gradient-parser": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/gradient-parser/-/gradient-parser-0.1.5.tgz", diff --git a/package.json b/package.json index 6d75792..3ad5fa6 100755 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "homepage": "https://github.com/catalinmiron/react-native-css-gradient#readme", "main": "index.js", "dependencies": { + "fast-memoize": "^2.5.1", "gradient-parser": "0.1.5" }, "peerDependencies": {