From 87d1eb880fba2ab05c85913a7f2432bf68120465 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sat, 22 Aug 2020 20:48:18 +0100 Subject: [PATCH 01/29] feat: First pass at a TS conversion --- .eslintrc | 23 ++++++++-- build-packages.js | 5 ++- package.json | 9 ++-- .../{ColorPicker.js => ColorPicker.tsx} | 18 +++++++- src/components/{HexInput.js => HexInput.tsx} | 9 +++- src/components/{Hue.js => Hue.tsx} | 7 ++- .../{Interactive.js => Interactive.tsx} | 14 ++++-- .../{Saturation.js => Saturation.tsx} | 8 +++- src/{index.js => index.ts} | 0 src/packages/{HexInput.js => HexInput.ts} | 0 src/packages/{hex.js => hex.tsx} | 0 src/packages/{hsl.js => hsl.tsx} | 0 src/packages/{hslString.js => hslString.tsx} | 0 src/packages/{hsv.js => hsv.tsx} | 0 src/packages/{rgb.js => rgb.tsx} | 0 src/packages/{rgbString.js => rgbString.tsx} | 0 src/styles.css.d.ts | 5 +++ src/types.ts | 32 ++++++++++++++ ...alColorObjects.js => equalColorObjects.ts} | 4 +- src/utils/{equalHex.js => equalHex.ts} | 2 +- ...{formatClassName.js => formatClassName.ts} | 0 src/utils/{hexToHsv.js => hexToHsv.ts} | 3 +- src/utils/{hexToRgb.js => hexToRgb.ts} | 4 +- .../{hslStringToHsv.js => hslStringToHsv.ts} | 0 src/utils/{hslToHsv.js => hslToHsv.ts} | 4 +- src/utils/{hsvToHex.js => hsvToHex.ts} | 3 +- src/utils/{hsvToHsl.js => hsvToHsl.ts} | 4 +- .../{hsvToHslString.js => hsvToHslString.ts} | 3 +- src/utils/{hsvToRgb.js => hsvToRgb.ts} | 6 ++- .../{hsvToRgbString.js => hsvToRgbString.ts} | 3 +- .../{rgbStringToHsv.js => rgbStringToHsv.ts} | 0 src/utils/{rgbToHex.js => rgbToHex.ts} | 0 src/utils/{rgbToHsv.js => rgbToHsv.ts} | 10 +++-- src/utils/{validHex.js => validHex.ts} | 2 +- tsconfig.build.json | 4 ++ tsconfig.json | 16 +++++++ types/index.d.ts | 44 ------------------- 37 files changed, 162 insertions(+), 80 deletions(-) rename src/components/{ColorPicker.js => ColorPicker.tsx} (83%) rename src/components/{HexInput.js => HexInput.tsx} (88%) rename src/components/{Hue.js => Hue.tsx} (89%) rename src/components/{Interactive.js => Interactive.tsx} (84%) rename src/components/{Saturation.js => Saturation.tsx} (88%) rename src/{index.js => index.ts} (100%) rename src/packages/{HexInput.js => HexInput.ts} (100%) rename src/packages/{hex.js => hex.tsx} (100%) rename src/packages/{hsl.js => hsl.tsx} (100%) rename src/packages/{hslString.js => hslString.tsx} (100%) rename src/packages/{hsv.js => hsv.tsx} (100%) rename src/packages/{rgb.js => rgb.tsx} (100%) rename src/packages/{rgbString.js => rgbString.tsx} (100%) create mode 100644 src/styles.css.d.ts create mode 100644 src/types.ts rename src/utils/{equalColorObjects.js => equalColorObjects.ts} (60%) rename src/utils/{equalHex.js => equalHex.ts} (79%) rename src/utils/{formatClassName.js => formatClassName.ts} (100%) rename src/utils/{hexToHsv.js => hexToHsv.ts} (50%) rename src/utils/{hexToRgb.js => hexToRgb.ts} (83%) rename src/utils/{hslStringToHsv.js => hslStringToHsv.ts} (100%) rename src/utils/{hslToHsv.js => hslToHsv.ts} (64%) rename src/utils/{hsvToHex.js => hsvToHex.ts} (50%) rename src/utils/{hsvToHsl.js => hsvToHsl.ts} (69%) rename src/utils/{hsvToHslString.js => hsvToHslString.ts} (64%) rename src/utils/{hsvToRgb.js => hsvToRgb.ts} (76%) rename src/utils/{hsvToRgbString.js => hsvToRgbString.ts} (64%) rename src/utils/{rgbStringToHsv.js => rgbStringToHsv.ts} (100%) rename src/utils/{rgbToHex.js => rgbToHex.ts} (100%) rename src/utils/{rgbToHsv.js => rgbToHsv.ts} (63%) rename src/utils/{validHex.js => validHex.ts} (52%) create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json delete mode 100644 types/index.d.ts diff --git a/.eslintrc b/.eslintrc index 7dc4f550..9f810595 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,8 @@ { "env": { "browser": true, - "es6": true + "es6": true, + "node": true }, "parserOptions": { "sourceType": "module" @@ -9,9 +10,13 @@ "plugins": ["prettier", "react"], "extends": [ "eslint:recommended", - "plugin:prettier/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", "plugin:react/recommended", - "plugin:react-hooks/recommended" + "plugin:react-hooks/recommended", + "plugin:prettier/recommended", + "prettier/@typescript-eslint", + "prettier/react" ], "rules": { "prettier/prettier": "error", @@ -21,5 +26,15 @@ "react": { "version": "detect" } - } + }, + "overrides": [ + { + "files": [ + "*.js" + ], + "rules": { + "@typescript-eslint/no-var-requires": [0] + } + } + ] } diff --git a/build-packages.js b/build-packages.js index 9424a78e..a45aa176 100644 --- a/build-packages.js +++ b/build-packages.js @@ -26,7 +26,7 @@ fs.readdir(entryDirPath, async (e, files) => { // Run microbundle const { stdout } = await exec( - `${bundlerPath} --entry ${filePath} --output ${outputDirPath}/index.js --name react-colorful-${name} --css-modules true --jsx React.createElement` + `${bundlerPath} --entry ${filePath} --output ${outputDirPath}/index.js --name react-colorful-${name} --css-modules true --jsx React.createElement --tsconfig tsconfig.build.json` ); console.log(stdout); @@ -35,10 +35,11 @@ fs.readdir(entryDirPath, async (e, files) => { var manifestCode = JSON.stringify({ name: `react-colorful-${name}`, private: true, + source: filePath, main: "index.js", module: "index.module.js", esmodule: "index.esmodule.js", - types: "../types/index.d.ts" + types: "index.d.ts", }); await writeFile(manifestPath, manifestCode, "utf8"); diff --git a/package.json b/package.json index d52b5627..5c04e79f 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,14 @@ "name": "react-colorful", "version": "2.2.0", "description": "A tiny color picker component for modern React apps", - "source": "src/index.js", + "source": "src/index.ts", "main": "dist/index.js", "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "types/index.d.ts", + "types": "dist/index.d.ts", "scripts": { - "lint": "eslint src/**/*.js demo/src/**/*.js", + "lint": "eslint src/**/*.{ts,tsx} demo/src/**/*.js", "size": "npm run build && size-limit", "test": "jest tests", "build": "node ./build-packages.js", @@ -96,6 +96,8 @@ "@size-limit/preset-small-lib": "^4.5.6", "@testing-library/react": "^10.4.8", "@types/react": "^16.9.46", + "@typescript-eslint/eslint-plugin": "^3.9.1", + "@typescript-eslint/parser": "^3.9.1", "del": "^5.1.0", "del-cli": "^3.0.1", "eslint": "^7.5.0", @@ -114,6 +116,7 @@ "react": "^16.8.0", "react-dom": "^16.8.0", "size-limit": "^4.5.5", + "typescript": "^4.0.2", "use-throttled-effect": "0.0.7" }, "dependencies": {} diff --git a/src/components/ColorPicker.js b/src/components/ColorPicker.tsx similarity index 83% rename from src/components/ColorPicker.js rename to src/components/ColorPicker.tsx index bcde937d..2a7fbe6c 100644 --- a/src/components/ColorPicker.js +++ b/src/components/ColorPicker.tsx @@ -1,14 +1,28 @@ import React, { useState, useEffect, useCallback, useRef } from "react"; + import Hue from "./Hue"; import Saturation from "./Saturation"; import formatClassName from "../utils/formatClassName"; import equalColorObjects from "../utils/equalColorObjects"; import styles from "../styles.css"; +import { ColorModel, Everything, HSV } from "../types"; + +interface Props { + className: string; + colorModel: ColorModel; + color: Everything; + onChange: (newColor: any) => void; +} -const ColorPicker = ({ className, colorModel, color = colorModel.defaultColor, onChange }) => { +const ColorPicker = ({ + className, + colorModel, + color = colorModel.defaultColor, + onChange, +}: Props) => { // No matter which color model is used (HEX, RGB or HSL), // all internal calculations are based on HSV model - const [hsv, updateHsv] = useState(() => colorModel.toHsv(color)); + const [hsv, updateHsv] = useState(() => colorModel.toHsv(color)); // By using this ref we're able to prevent extra updates // and the effects recursion during the color conversion diff --git a/src/components/HexInput.js b/src/components/HexInput.tsx similarity index 88% rename from src/components/HexInput.js rename to src/components/HexInput.tsx index 2cc82832..edaa3f89 100644 --- a/src/components/HexInput.js +++ b/src/components/HexInput.tsx @@ -2,9 +2,14 @@ import React, { useState, useEffect, useCallback } from "react"; import validHex from "../utils/validHex"; // Escapes all non-hexadecimal characters including "#" -const escape = (hex) => hex.replace(/([^0-9A-F]+)/gi, ""); +const escape = (hex: string) => hex.replace(/([^0-9A-F]+)/gi, ""); -const HexInput = (props) => { +interface Props { + color: string; + onChange: (newColor: any) => void; +} + +const HexInput = (props: Props) => { const { color, onChange } = props; const [value, setValue] = useState(escape(color)); diff --git a/src/components/Hue.js b/src/components/Hue.tsx similarity index 89% rename from src/components/Hue.js rename to src/components/Hue.tsx index 2871f917..ae03213f 100644 --- a/src/components/Hue.js +++ b/src/components/Hue.tsx @@ -4,7 +4,12 @@ import formatClassName from "../utils/formatClassName"; import hsvToHslString from "../utils/hsvToHslString"; import styles from "../styles.css"; -const Hue = ({ hue, onChange }) => { +interface Props { + hue: number; + onChange: (newColor: any) => void; +} + +const Hue = ({ hue, onChange }: Props) => { const handleMove = useCallback( (interaction) => { // Hue measured in degrees of the color circle ranging from 0 to 360 diff --git a/src/components/Interactive.js b/src/components/Interactive.tsx similarity index 84% rename from src/components/Interactive.js rename to src/components/Interactive.tsx index f84f14a3..be7eb42f 100644 --- a/src/components/Interactive.js +++ b/src/components/Interactive.tsx @@ -3,13 +3,19 @@ import styles from "../styles.css"; // Limit number within [0, 1] bounds. // Use ternary operator instead of `Math.min(Math.max(0, number), 1)` to save few bytes -const limit = (number) => (number > 1 ? 1 : number < 0 ? 0 : number); +const limit = (number: number) => (number > 1 ? 1 : number < 0 ? 0 : number); -const Interactive = ({ onMove, children }) => { - const container = useRef(); +interface Props { + onMove: (interaction: any) => void; + children: React.ReactNode; +} + +const Interactive = ({ onMove, children }: Props) => { + const container = useRef(null); const [isDragging, setDragging] = useState(false); const getRelativePosition = useCallback((event) => { + if (!container.current) return; const rect = container.current.getBoundingClientRect(); const pointer = typeof event.pageX === "number" ? event : event.touches[0]; @@ -51,7 +57,7 @@ const Interactive = ({ onMove, children }) => { useLayoutEffect(() => { toggleDocumentEvents(isDragging); - return () => isDragging && toggleDocumentEvents(false); + if (isDragging) toggleDocumentEvents(false); }, [isDragging, toggleDocumentEvents]); return ( diff --git a/src/components/Saturation.js b/src/components/Saturation.tsx similarity index 88% rename from src/components/Saturation.js rename to src/components/Saturation.tsx index 6ab6108f..dcd1e80b 100644 --- a/src/components/Saturation.js +++ b/src/components/Saturation.tsx @@ -3,8 +3,14 @@ import Interactive from "./Interactive"; import formatClassName from "../utils/formatClassName"; import styles from "../styles.css"; import hsvToHslString from "../utils/hsvToHslString"; +import { HSV } from "../types"; -const Saturation = ({ hsv, onChange }) => { +interface Props { + hsv: HSV; + onChange: (newColor: any) => void; +} + +const Saturation = ({ hsv, onChange }: Props) => { const handleMove = useCallback( (interaction) => { // Saturation and brightness always fit into [0, 100] range diff --git a/src/index.js b/src/index.ts similarity index 100% rename from src/index.js rename to src/index.ts diff --git a/src/packages/HexInput.js b/src/packages/HexInput.ts similarity index 100% rename from src/packages/HexInput.js rename to src/packages/HexInput.ts diff --git a/src/packages/hex.js b/src/packages/hex.tsx similarity index 100% rename from src/packages/hex.js rename to src/packages/hex.tsx diff --git a/src/packages/hsl.js b/src/packages/hsl.tsx similarity index 100% rename from src/packages/hsl.js rename to src/packages/hsl.tsx diff --git a/src/packages/hslString.js b/src/packages/hslString.tsx similarity index 100% rename from src/packages/hslString.js rename to src/packages/hslString.tsx diff --git a/src/packages/hsv.js b/src/packages/hsv.tsx similarity index 100% rename from src/packages/hsv.js rename to src/packages/hsv.tsx diff --git a/src/packages/rgb.js b/src/packages/rgb.tsx similarity index 100% rename from src/packages/rgb.js rename to src/packages/rgb.tsx diff --git a/src/packages/rgbString.js b/src/packages/rgbString.tsx similarity index 100% rename from src/packages/rgbString.js rename to src/packages/rgbString.tsx diff --git a/src/styles.css.d.ts b/src/styles.css.d.ts new file mode 100644 index 00000000..c4e60dbb --- /dev/null +++ b/src/styles.css.d.ts @@ -0,0 +1,5 @@ +export const container: string; +export const saturation: string; +export const hue: string; +export const interactive: string; +export const pointer: string; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..37f4254d --- /dev/null +++ b/src/types.ts @@ -0,0 +1,32 @@ +export interface RGB { + r: number; + g: number; + b: number; +} + +export interface HSL { + h: number; + s: number; + l: number; +} + +export interface HSV { + h: number; + s: number; + v: number; +} + +export type Everything = string | RGB | HSL | HSV; + +export interface ColorModel { + defaultColor: Everything; + toHsv: (defaultColor: any) => HSV; + fromHsv: (hsv: HSV) => Everything; + equal: (first: any, second: any) => boolean; +} + +export interface BaseComponentProps { + className: string; + color: any; + onChange: (newColor: any) => void; +} diff --git a/src/utils/equalColorObjects.js b/src/utils/equalColorObjects.ts similarity index 60% rename from src/utils/equalColorObjects.js rename to src/utils/equalColorObjects.ts index 726d0b99..6a2a333b 100644 --- a/src/utils/equalColorObjects.js +++ b/src/utils/equalColorObjects.ts @@ -1,7 +1,7 @@ -const equalColorObjects = (first, second) => { +const equalColorObjects = (first: any, second: any): boolean => { if (first === second) return true; - for (let prop in first) { + for (const prop in first) { if (first[prop] !== second[prop]) return false; } diff --git a/src/utils/equalHex.js b/src/utils/equalHex.ts similarity index 79% rename from src/utils/equalHex.js rename to src/utils/equalHex.ts index afd5d093..4cf573d5 100644 --- a/src/utils/equalHex.js +++ b/src/utils/equalHex.ts @@ -1,7 +1,7 @@ import hexToRgb from "./hexToRgb"; import equalColorObjects from "./equalColorObjects"; -const equalHex = (first, second) => { +const equalHex = (first: string, second: string): boolean => { if (first.toLowerCase() === second.toLowerCase()) return true; return equalColorObjects(hexToRgb(first), hexToRgb(second)); diff --git a/src/utils/formatClassName.js b/src/utils/formatClassName.ts similarity index 100% rename from src/utils/formatClassName.js rename to src/utils/formatClassName.ts diff --git a/src/utils/hexToHsv.js b/src/utils/hexToHsv.ts similarity index 50% rename from src/utils/hexToHsv.js rename to src/utils/hexToHsv.ts index f3f839bb..aa143123 100644 --- a/src/utils/hexToHsv.js +++ b/src/utils/hexToHsv.ts @@ -1,6 +1,7 @@ import hexToRgb from "./hexToRgb"; import rgbToHsv from "./rgbToHsv"; +import { HSV } from "../types"; -const hexToHsv = (hex) => rgbToHsv(hexToRgb(hex)); +const hexToHsv = (hex: string): HSV => rgbToHsv(hexToRgb(hex)); export default hexToHsv; diff --git a/src/utils/hexToRgb.js b/src/utils/hexToRgb.ts similarity index 83% rename from src/utils/hexToRgb.js rename to src/utils/hexToRgb.ts index b3fe9b0e..241da32b 100644 --- a/src/utils/hexToRgb.js +++ b/src/utils/hexToRgb.ts @@ -1,4 +1,6 @@ -const hexToRgb = (hex) => { +import { RGB } from "../types"; + +const hexToRgb = (hex: string): RGB => { if (hex[0] === "#") hex = hex.substr(1); if (hex.length < 6) { diff --git a/src/utils/hslStringToHsv.js b/src/utils/hslStringToHsv.ts similarity index 100% rename from src/utils/hslStringToHsv.js rename to src/utils/hslStringToHsv.ts diff --git a/src/utils/hslToHsv.js b/src/utils/hslToHsv.ts similarity index 64% rename from src/utils/hslToHsv.js rename to src/utils/hslToHsv.ts index a3a3981b..66a8c9a3 100644 --- a/src/utils/hslToHsv.js +++ b/src/utils/hslToHsv.ts @@ -1,4 +1,6 @@ -const hslToHsv = ({ h, s, l }) => { +import { HSL, HSV } from "../types"; + +const hslToHsv = ({ h, s, l }: HSL): HSV => { s *= (l < 50 ? l : 100 - l) / 100; return { diff --git a/src/utils/hsvToHex.js b/src/utils/hsvToHex.ts similarity index 50% rename from src/utils/hsvToHex.js rename to src/utils/hsvToHex.ts index 690030d1..84be0295 100644 --- a/src/utils/hsvToHex.js +++ b/src/utils/hsvToHex.ts @@ -1,6 +1,7 @@ import rgbToHex from "./rgbToHex"; import hsvToRgb from "./hsvToRgb"; +import { HSV } from "../types"; -const hsvToHex = (hex) => rgbToHex(hsvToRgb(hex)); +const hsvToHex = (hsv: HSV): string => rgbToHex(hsvToRgb(hsv)); export default hsvToHex; diff --git a/src/utils/hsvToHsl.js b/src/utils/hsvToHsl.ts similarity index 69% rename from src/utils/hsvToHsl.js rename to src/utils/hsvToHsl.ts index b2d430b7..f2c1c5a8 100644 --- a/src/utils/hsvToHsl.js +++ b/src/utils/hsvToHsl.ts @@ -1,4 +1,6 @@ -const hsvToHsl = ({ h, s, v }) => { +import { HSL, HSV } from "../types"; + +const hsvToHsl = ({ h, s, v }: HSV): HSL => { const hh = ((200 - s) * v) / 100; return { diff --git a/src/utils/hsvToHslString.js b/src/utils/hsvToHslString.ts similarity index 64% rename from src/utils/hsvToHslString.js rename to src/utils/hsvToHslString.ts index 860cb70c..a008a2e5 100644 --- a/src/utils/hsvToHslString.js +++ b/src/utils/hsvToHslString.ts @@ -1,6 +1,7 @@ import hsvToHsl from "./hsvToHsl"; +import { HSV } from "../types"; -const hsvToHslString = (hsv) => { +const hsvToHslString = (hsv: HSV): string => { const { h, s, l } = hsvToHsl(hsv); return `hsl(${h}, ${s}%, ${l}%)`; }; diff --git a/src/utils/hsvToRgb.js b/src/utils/hsvToRgb.ts similarity index 76% rename from src/utils/hsvToRgb.js rename to src/utils/hsvToRgb.ts index 2250e939..621a483b 100644 --- a/src/utils/hsvToRgb.js +++ b/src/utils/hsvToRgb.ts @@ -1,9 +1,11 @@ -const hsvToRgb = ({ h, s, v }) => { +import { HSV, RGB } from "../types"; + +const hsvToRgb = ({ h, s, v }: HSV): RGB => { h = (h / 360) * 6; s = s / 100; v = v / 100; - let hh = Math.floor(h), + const hh = Math.floor(h), b = v * (1 - s), c = v * (1 - (h - hh) * s), d = v * (1 - (1 - h + hh) * s), diff --git a/src/utils/hsvToRgbString.js b/src/utils/hsvToRgbString.ts similarity index 64% rename from src/utils/hsvToRgbString.js rename to src/utils/hsvToRgbString.ts index 1bdd073b..91913e52 100644 --- a/src/utils/hsvToRgbString.js +++ b/src/utils/hsvToRgbString.ts @@ -1,6 +1,7 @@ import hsvToRgb from "./hsvToRgb"; +import { HSV } from "../types"; -const hsvToRgbString = (hsv) => { +const hsvToRgbString = (hsv: HSV): string => { const { r, g, b } = hsvToRgb(hsv); return `rgb(${r}, ${g}, ${b})`; }; diff --git a/src/utils/rgbStringToHsv.js b/src/utils/rgbStringToHsv.ts similarity index 100% rename from src/utils/rgbStringToHsv.js rename to src/utils/rgbStringToHsv.ts diff --git a/src/utils/rgbToHex.js b/src/utils/rgbToHex.ts similarity index 100% rename from src/utils/rgbToHex.js rename to src/utils/rgbToHex.ts diff --git a/src/utils/rgbToHsv.js b/src/utils/rgbToHsv.ts similarity index 63% rename from src/utils/rgbToHsv.js rename to src/utils/rgbToHsv.ts index 8db17b73..30d8328b 100644 --- a/src/utils/rgbToHsv.js +++ b/src/utils/rgbToHsv.ts @@ -1,8 +1,10 @@ -const rgbToHsv = ({ r, g, b }) => { - let max = Math.max(r, g, b); - let delta = max - Math.min(r, g, b); +import { HSV, RGB } from "../types"; - let hh = delta +const rgbToHsv = ({ r, g, b }: RGB): HSV => { + const max = Math.max(r, g, b); + const delta = max - Math.min(r, g, b); + + const hh = delta ? max === r ? (g - b) / delta : max === g diff --git a/src/utils/validHex.js b/src/utils/validHex.ts similarity index 52% rename from src/utils/validHex.js rename to src/utils/validHex.ts index f85632e6..299a11cc 100644 --- a/src/utils/validHex.js +++ b/src/utils/validHex.ts @@ -1,6 +1,6 @@ const hex3 = /^#?[0-9A-F]{3}$/i; const hex6 = /^#?[0-9A-F]{6}$/i; -const validHex = (color) => hex6.test(color) || hex3.test(color); +const validHex = (color: string): boolean => hex6.test(color) || hex3.test(color); export default validHex; diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..e9041fd6 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..6ee17cbf --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "esModuleInterop": true, + "jsx": "react", + "jsxFactory": "React.createElement", + "moduleResolution": "node", + "noImplicitAny": true, + "outDir": "dist", + "declaration": true, + "resolveJsonModule": true, + "strict": true + }, + "include": ["src", "test"] +} \ No newline at end of file diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index c089f4e8..00000000 --- a/types/index.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -declare module "react-colorful" { - import { FC } from "react"; - const ColorPicker: FC<{ className: string; color: string; onChange: (newColor: string) => void }>; - export = ColorPicker; -} - -declare module "react-colorful/rgb" { - import { FC } from "react"; - type rgb = { r: number; g: number; b: number }; - const ColorPicker: FC<{ className: string; color: rgb; onChange: (newColor: rgb) => void }>; - export = ColorPicker; -} - -declare module "react-colorful/rgbString" { - import { FC } from "react"; - const ColorPicker: FC<{ className: string; color: string; onChange: (newColor: string) => void }>; - export = ColorPicker; -} - -declare module "react-colorful/hsl" { - import { FC } from "react"; - type hsl = { h: number; s: number; l: number }; - const ColorPicker: FC<{ className: string; color: hsl; onChange: (newColor: hsl) => void }>; - export = ColorPicker; -} - -declare module "react-colorful/hslString" { - import { FC } from "react"; - const ColorPicker: FC<{ className: string; color: string; onChange: (newColor: string) => void }>; - export = ColorPicker; -} - -declare module "react-colorful/hsv" { - import { FC } from "react"; - type hsv = { h: number; s: number; v: number }; - const ColorPicker: FC<{ className: string; color: hsv; onChange: (newColor: hsv) => void }>; - export = ColorPicker; -} - -declare module "react-colorful/HexInput" { - import { FC } from "react"; - const HexInput: FC<{ color: string; onChange: (newColor: string) => void }>; - export = HexInput; -} From 47ed0eac0a91368b3da3547de3f1346e150a5ea0 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sat, 22 Aug 2020 20:51:01 +0100 Subject: [PATCH 02/29] fix: Had to break into separate commits to keep history --- src/packages/hex.tsx | 30 ++++++++++++++++++++++-------- src/packages/hsl.tsx | 30 ++++++++++++++++++++++-------- src/packages/hslString.tsx | 30 ++++++++++++++++++++++-------- src/packages/hsv.tsx | 30 ++++++++++++++++++++++-------- src/packages/rgb.tsx | 30 ++++++++++++++++++++++-------- src/packages/rgbString.tsx | 30 ++++++++++++++++++++++-------- src/utils/formatClassName.ts | 2 +- src/utils/hslStringToHsv.ts | 11 ++++++----- src/utils/rgbStringToHsv.ts | 9 +++++---- src/utils/rgbToHex.ts | 6 ++++-- 10 files changed, 148 insertions(+), 60 deletions(-) diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index c00c76b1..603ee631 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -4,14 +4,28 @@ import ColorPicker from "../components/ColorPicker"; import toHsv from "../utils/hexToHsv"; import fromHsv from "../utils/hsvToHex"; import equal from "../utils/equalHex"; +import { BaseComponentProps } from "../types"; -const HEX = { - defaultColor: "000", - toHsv, - fromHsv, - equal, -}; +interface Props extends BaseComponentProps { + className: string; + color: string; + onChange: (newColor: string) => void; +} -ColorPicker.defaultProps = { colorModel: HEX }; +const Hex: React.FC = (props) => { + return ( + + ); +}; -export default React.memo(ColorPicker); +export default React.memo(Hex); diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index 4a31ee7c..23e8891f 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -4,14 +4,28 @@ import ColorPicker from "../components/ColorPicker"; import toHsv from "../utils/hslToHsv"; import fromHsv from "../utils/hsvToHsl"; import equal from "../utils/equalColorObjects"; +import { BaseComponentProps, HSL } from "../types"; -const HSL = { - defaultColor: { h: 0, s: 0, l: 0 }, - toHsv, - fromHsv, - equal, -}; +interface Props extends BaseComponentProps { + className: string; + color: HSL; + onChange: (newColor: HSL) => void; +} -ColorPicker.defaultProps = { colorModel: HSL }; +const Hsl: React.FC = (props) => { + return ( + + ); +}; -export default React.memo(ColorPicker); +export default React.memo(Hsl); diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index f0e7e7bb..341c91e1 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -4,14 +4,28 @@ import ColorPicker from "../components/ColorPicker"; import toHsv from "../utils/hslStringToHsv"; import fromHsv from "../utils/hsvToHslString"; import equal from "../utils/equalColorObjects"; +import { BaseComponentProps } from "../types"; -const HSL_STRING = { - defaultColor: "hsl(0, 0%, 0%)", - toHsv, - fromHsv, - equal, -}; +interface Props extends BaseComponentProps { + className: string; + color: string; + onChange: (newColor: string) => void; +} -ColorPicker.defaultProps = { colorModel: HSL_STRING }; +const HslString: React.FC = (props) => { + return ( + + ); +}; -export default React.memo(ColorPicker); +export default React.memo(HslString); diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index fcf92462..e108251e 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -2,14 +2,28 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import equal from "../utils/equalColorObjects"; +import { BaseComponentProps, HSV } from "../types"; -const HSV = { - defaultColor: { h: 0, s: 0, v: 0 }, - toHsv: (hsv) => hsv, - fromHsv: (hsv) => hsv, - equal, -}; +interface Props extends BaseComponentProps { + className: string; + color: HSV; + onChange: (newColor: HSV) => void; +} -ColorPicker.defaultProps = { colorModel: HSV }; +const Hsv: React.FC = (props) => { + return ( + hsv, + fromHsv: (hsv) => hsv, + equal, + }} + color={props.color} + onChange={props.onChange} + /> + ); +}; -export default React.memo(ColorPicker); +export default React.memo(Hsv); diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index b8d1bcfb..7dd0d98d 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -4,14 +4,28 @@ import ColorPicker from "../components/ColorPicker"; import toHsv from "../utils/rgbToHsv"; import fromHsv from "../utils/hsvToRgb"; import equal from "../utils/equalColorObjects"; +import { BaseComponentProps, RGB } from "../types"; -const RGB = { - defaultColor: { r: 0, g: 0, b: 0 }, - toHsv, - fromHsv, - equal, -}; +interface Props extends BaseComponentProps { + className: string; + color: RGB; + onChange: (newColor: RGB) => void; +} -ColorPicker.defaultProps = { colorModel: RGB }; +const Rgb: React.FC = (props) => { + return ( + + ); +}; -export default React.memo(ColorPicker); +export default React.memo(Rgb); diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index f04633a8..7b8ae579 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -4,14 +4,28 @@ import ColorPicker from "../components/ColorPicker"; import toHsv from "../utils/rgbStringToHsv"; import fromHsv from "../utils/hsvToRgbString"; import equal from "../utils/equalColorObjects"; +import { BaseComponentProps } from "../types"; -const HSL_STRING = { - defaultColor: "rgb(0, 0, 0)", - toHsv, - fromHsv, - equal, -}; +interface Props extends BaseComponentProps { + className: string; + color: string; + onChange: (newColor: string) => void; +} -ColorPicker.defaultProps = { colorModel: HSL_STRING }; +const RgbString: React.FC = (props) => { + return ( + + ); +}; -export default React.memo(ColorPicker); +export default React.memo(RgbString); diff --git a/src/utils/formatClassName.ts b/src/utils/formatClassName.ts index 04968af3..588dd08b 100644 --- a/src/utils/formatClassName.ts +++ b/src/utils/formatClassName.ts @@ -1,3 +1,3 @@ -const formatClassName = (array) => array.filter(Boolean).join(" "); +const formatClassName = (names: string[]): string => names.filter(Boolean).join(" "); export default formatClassName; diff --git a/src/utils/hslStringToHsv.ts b/src/utils/hslStringToHsv.ts index 040d75cc..7267719e 100644 --- a/src/utils/hslStringToHsv.ts +++ b/src/utils/hslStringToHsv.ts @@ -1,14 +1,15 @@ import hslToHsv from "./hslToHsv"; +import { HSV } from "../types"; const matcher = /hsl\((\d+(?:\.\d+)*),\s*(\d+(?:\.\d+)*)%?,\s*(\d+(?:\.\d+)*)%?\)/; -const hslStringToHsv = (string) => { - const match = matcher.exec(string); +const hslStringToHsv = (hslString: string): HSV => { + const match = matcher.exec(hslString); return hslToHsv({ - h: Number(match[1]), - s: Number(match[2]), - l: Number(match[3]), + h: Number(match ? match : [1]), + s: Number(match ? match : [2]), + l: Number(match ? match : [3]), }); }; diff --git a/src/utils/rgbStringToHsv.ts b/src/utils/rgbStringToHsv.ts index e62c2482..a226d128 100644 --- a/src/utils/rgbStringToHsv.ts +++ b/src/utils/rgbStringToHsv.ts @@ -1,14 +1,15 @@ import rgbToHsv from "./rgbToHsv"; +import { HSV } from "../types"; const matcher = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/; -const rgbStringToHsv = (string) => { +const rgbStringToHsv = (string: string): HSV => { const match = matcher.exec(string); return rgbToHsv({ - r: Number(match[1]), - g: Number(match[2]), - b: Number(match[3]), + r: Number(match ? match : [1]), + g: Number(match ? match : [2]), + b: Number(match ? match : [3]), }); }; diff --git a/src/utils/rgbToHex.ts b/src/utils/rgbToHex.ts index ae9caa29..97f6b6f6 100644 --- a/src/utils/rgbToHex.ts +++ b/src/utils/rgbToHex.ts @@ -1,8 +1,10 @@ -const format = (number) => { +import { RGB } from "../types"; + +const format = (number: number) => { const hex = number.toString(16); return hex.length < 2 ? "0" + hex : hex; }; -const rgbToHex = ({ r, g, b }) => "#" + format(r) + format(g) + format(b); +const rgbToHex = ({ r, g, b }: RGB): string => "#" + format(r) + format(g) + format(b); export default rgbToHex; From e488b03d541c5f2e86b72d61b66dbd98b9a93e19 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 03:54:12 +0100 Subject: [PATCH 03/29] fix: Correcting Jest with TS --- .eslintrc | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/.eslintrc b/.eslintrc index 9f810595..b2e52374 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,6 +2,7 @@ "env": { "browser": true, "es6": true, + "jest": true, "node": true }, "parserOptions": { diff --git a/package.json b/package.json index 5c04e79f..0561ac4b 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "devDependencies": { "@size-limit/preset-small-lib": "^4.5.6", "@testing-library/react": "^10.4.8", + "@types/jest": "^26.0.10", "@types/react": "^16.9.46", "@typescript-eslint/eslint-plugin": "^3.9.1", "@typescript-eslint/parser": "^3.9.1", From 7b0b93e76c1c4d2f8c606af5749eb05fdd784a64 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 04:22:01 +0100 Subject: [PATCH 04/29] refactor: Move all type conversions into `conversions.ts` Attempting to clean up imports a bit --- src/components/ColorPicker.tsx | 5 +- src/components/HexInput.tsx | 1 + src/components/Hue.tsx | 6 +- src/components/Interactive.tsx | 1 + src/components/Saturation.tsx | 6 +- src/packages/hex.tsx | 11 ++- src/packages/hsl.tsx | 11 ++- src/packages/hslString.tsx | 11 ++- src/packages/hsv.tsx | 6 +- src/packages/rgb.tsx | 11 ++- src/packages/rgbString.tsx | 9 ++- src/utils/conversions.ts | 120 +++++++++++++++++++++++++++++++++ src/utils/equalHex.ts | 2 +- src/utils/hexToHsv.ts | 7 -- src/utils/hexToRgb.ts | 21 ------ src/utils/hslStringToHsv.ts | 16 ----- src/utils/hslToHsv.ts | 13 ---- src/utils/hsvToHex.ts | 7 -- src/utils/hsvToHsl.ts | 13 ---- src/utils/hsvToHslString.ts | 9 --- src/utils/hsvToRgb.ts | 21 ------ src/utils/hsvToRgbString.ts | 9 --- src/utils/rgbStringToHsv.ts | 16 ----- src/utils/rgbToHex.ts | 10 --- src/utils/rgbToHsv.ts | 22 ------ tsconfig.json | 1 - 26 files changed, 161 insertions(+), 204 deletions(-) create mode 100644 src/utils/conversions.ts delete mode 100644 src/utils/hexToHsv.ts delete mode 100644 src/utils/hexToRgb.ts delete mode 100644 src/utils/hslStringToHsv.ts delete mode 100644 src/utils/hslToHsv.ts delete mode 100644 src/utils/hsvToHex.ts delete mode 100644 src/utils/hsvToHsl.ts delete mode 100644 src/utils/hsvToHslString.ts delete mode 100644 src/utils/hsvToRgb.ts delete mode 100644 src/utils/hsvToRgbString.ts delete mode 100644 src/utils/rgbStringToHsv.ts delete mode 100644 src/utils/rgbToHex.ts delete mode 100644 src/utils/rgbToHsv.ts diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 2a7fbe6c..c32e86e9 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -2,10 +2,11 @@ import React, { useState, useEffect, useCallback, useRef } from "react"; import Hue from "./Hue"; import Saturation from "./Saturation"; -import formatClassName from "../utils/formatClassName"; -import equalColorObjects from "../utils/equalColorObjects"; + import styles from "../styles.css"; import { ColorModel, Everything, HSV } from "../types"; +import formatClassName from "../utils/formatClassName"; +import equalColorObjects from "../utils/equalColorObjects"; interface Props { className: string; diff --git a/src/components/HexInput.tsx b/src/components/HexInput.tsx index edaa3f89..20753722 100644 --- a/src/components/HexInput.tsx +++ b/src/components/HexInput.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback } from "react"; + import validHex from "../utils/validHex"; // Escapes all non-hexadecimal characters including "#" diff --git a/src/components/Hue.tsx b/src/components/Hue.tsx index ae03213f..17d0f6a6 100644 --- a/src/components/Hue.tsx +++ b/src/components/Hue.tsx @@ -1,8 +1,10 @@ import React, { useCallback } from "react"; + import Interactive from "./Interactive"; -import formatClassName from "../utils/formatClassName"; -import hsvToHslString from "../utils/hsvToHslString"; + import styles from "../styles.css"; +import formatClassName from "../utils/formatClassName"; +import { hsvToHslString } from "../utils/conversions"; interface Props { hue: number; diff --git a/src/components/Interactive.tsx b/src/components/Interactive.tsx index be7eb42f..ca55722a 100644 --- a/src/components/Interactive.tsx +++ b/src/components/Interactive.tsx @@ -1,4 +1,5 @@ import React, { useState, useLayoutEffect, useRef, useCallback } from "react"; + import styles from "../styles.css"; // Limit number within [0, 1] bounds. diff --git a/src/components/Saturation.tsx b/src/components/Saturation.tsx index dcd1e80b..3945cc12 100644 --- a/src/components/Saturation.tsx +++ b/src/components/Saturation.tsx @@ -1,9 +1,11 @@ import React, { useCallback } from "react"; + import Interactive from "./Interactive"; -import formatClassName from "../utils/formatClassName"; + import styles from "../styles.css"; -import hsvToHslString from "../utils/hsvToHslString"; import { HSV } from "../types"; +import { hsvToHslString } from "../utils/conversions"; +import formatClassName from "../utils/formatClassName"; interface Props { hsv: HSV; diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index 603ee631..fb430e70 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -1,10 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import toHsv from "../utils/hexToHsv"; -import fromHsv from "../utils/hsvToHex"; -import equal from "../utils/equalHex"; +import ColorPicker from "../components/ColorPicker"; import { BaseComponentProps } from "../types"; +import { hexToHsv, hsvToHex } from "../utils/conversions"; +import equal from "../utils/equalHex"; interface Props extends BaseComponentProps { className: string; @@ -18,8 +17,8 @@ const Hex: React.FC = (props) => { className={props.className} colorModel={{ defaultColor: "000", - toHsv, - fromHsv, + toHsv: hexToHsv, + fromHsv: hsvToHex, equal, }} color={props.color} diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index 23e8891f..82daa3eb 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -1,10 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import toHsv from "../utils/hslToHsv"; -import fromHsv from "../utils/hsvToHsl"; -import equal from "../utils/equalColorObjects"; +import ColorPicker from "../components/ColorPicker"; import { BaseComponentProps, HSL } from "../types"; +import { hslToHsv, hsvToHsl } from "../utils/conversions"; +import equal from "../utils/equalColorObjects"; interface Props extends BaseComponentProps { className: string; @@ -18,8 +17,8 @@ const Hsl: React.FC = (props) => { className={props.className} colorModel={{ defaultColor: { h: 0, s: 0, l: 0 }, - toHsv, - fromHsv, + toHsv: hslToHsv, + fromHsv: hsvToHsl, equal, }} color={props.color} diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index 341c91e1..53e1a780 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -1,10 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import toHsv from "../utils/hslStringToHsv"; -import fromHsv from "../utils/hsvToHslString"; -import equal from "../utils/equalColorObjects"; +import ColorPicker from "../components/ColorPicker"; import { BaseComponentProps } from "../types"; +import { hslStringToHsv, hsvToHslString } from "../utils/conversions"; +import equal from "../utils/equalColorObjects"; interface Props extends BaseComponentProps { className: string; @@ -18,8 +17,8 @@ const HslString: React.FC = (props) => { className={props.className} colorModel={{ defaultColor: "hsl(0, 0%, 0%)", - toHsv, - fromHsv, + toHsv: hslStringToHsv, + fromHsv: hsvToHslString, equal, }} color={props.color} diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index e108251e..ccdd0ee4 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -1,8 +1,8 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import equal from "../utils/equalColorObjects"; +import ColorPicker from "../components/ColorPicker"; import { BaseComponentProps, HSV } from "../types"; +import equal from "../utils/equalColorObjects"; interface Props extends BaseComponentProps { className: string; @@ -16,7 +16,7 @@ const Hsv: React.FC = (props) => { className={props.className} colorModel={{ defaultColor: { h: 0, s: 0, v: 0 }, - toHsv: (hsv) => hsv, + toHsv: (hsv: HSV) => hsv, fromHsv: (hsv) => hsv, equal, }} diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 7dd0d98d..04d4fddb 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -1,10 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import toHsv from "../utils/rgbToHsv"; -import fromHsv from "../utils/hsvToRgb"; -import equal from "../utils/equalColorObjects"; +import ColorPicker from "../components/ColorPicker"; import { BaseComponentProps, RGB } from "../types"; +import { rgbToHsv, hsvToRgb } from "../utils/conversions"; +import equal from "../utils/equalColorObjects"; interface Props extends BaseComponentProps { className: string; @@ -18,8 +17,8 @@ const Rgb: React.FC = (props) => { className={props.className} colorModel={{ defaultColor: { r: 0, g: 0, b: 0 }, - toHsv, - fromHsv, + toHsv: rgbToHsv, + fromHsv: hsvToRgb, equal, }} color={props.color} diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 7b8ae579..064b40b1 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -1,8 +1,7 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import toHsv from "../utils/rgbStringToHsv"; -import fromHsv from "../utils/hsvToRgbString"; +import ColorPicker from "../components/ColorPicker"; +import { rgbStringToHsv, hsvToRgbString } from "../utils/conversions"; import equal from "../utils/equalColorObjects"; import { BaseComponentProps } from "../types"; @@ -18,8 +17,8 @@ const RgbString: React.FC = (props) => { className={props.className} colorModel={{ defaultColor: "rgb(0, 0, 0)", - toHsv, - fromHsv, + toHsv: rgbStringToHsv, + fromHsv: hsvToRgbString, equal, }} color={props.color} diff --git a/src/utils/conversions.ts b/src/utils/conversions.ts new file mode 100644 index 00000000..2e00518e --- /dev/null +++ b/src/utils/conversions.ts @@ -0,0 +1,120 @@ +import { HSL, HSV, RGB } from "../types"; + +export const hexToHsv = (hex: string): HSV => rgbToHsv(hexToRgb(hex)); + +export const hexToRgb = (hex: string): RGB => { + if (hex[0] === "#") hex = hex.substr(1); + + if (hex.length < 6) { + return { + r: parseInt(hex[0] + hex[0], 16), + g: parseInt(hex[1] + hex[1], 16), + b: parseInt(hex[2] + hex[2], 16), + }; + } + + return { + r: parseInt(hex.substr(0, 2), 16), + g: parseInt(hex.substr(2, 2), 16), + b: parseInt(hex.substr(4, 2), 16), + }; +}; + +export const hslStringToHsv = (hslString: string): HSV => { + const matcher = /hsl\((\d+(?:\.\d+)*),\s*(\d+(?:\.\d+)*)%?,\s*(\d+(?:\.\d+)*)%?\)/; + const match = matcher.exec(hslString); + + return hslToHsv({ + h: Number(match ? match : [1]), + s: Number(match ? match : [2]), + l: Number(match ? match : [3]), + }); +}; + +export const hslToHsv = ({ h, s, l }: HSL): HSV => { + s *= (l < 50 ? l : 100 - l) / 100; + + return { + h: h, + s: s > 0 ? ((2 * s) / (l + s)) * 100 : 0, + v: l + s, + }; +}; + +export const hsvToHex = (hsv: HSV): string => rgbToHex(hsvToRgb(hsv)); + +export const hsvToHsl = ({ h, s, v }: HSV): HSL => { + const hh = ((200 - s) * v) / 100; + + return { + h: h, + s: hh > 0 && hh < 200 ? ((s * v) / 100 / (hh <= 100 ? hh : 200 - hh)) * 100 : 0, + l: hh / 2, + }; +}; + +export const hsvToHslString = (hsv: HSV): string => { + const { h, s, l } = hsvToHsl(hsv); + return `hsl(${h}, ${s}%, ${l}%)`; +}; + +export const hsvToRgb = ({ h, s, v }: HSV): RGB => { + h = (h / 360) * 6; + s = s / 100; + v = v / 100; + + const hh = Math.floor(h), + b = v * (1 - s), + c = v * (1 - (h - hh) * s), + d = v * (1 - (1 - h + hh) * s), + module = hh % 6; + + return { + r: Math.round([v, c, b, b, d, v][module] * 255), + g: Math.round([d, v, v, c, b, b][module] * 255), + b: Math.round([b, b, d, v, v, c][module] * 255), + }; +}; + +export const hsvToRgbString = (hsv: HSV): string => { + const { r, g, b } = hsvToRgb(hsv); + return `rgb(${r}, ${g}, ${b})`; +}; + +export const rgbStringToHsv = (rgbString: string): HSV => { + const matcher = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/; + const match = matcher.exec(rgbString); + + return rgbToHsv({ + r: Number(match ? match : [1]), + g: Number(match ? match : [2]), + b: Number(match ? match : [3]), + }); +}; + +const format = (number: number) => { + const hex = number.toString(16); + return hex.length < 2 ? "0" + hex : hex; +}; + +export const rgbToHex = ({ r, g, b }: RGB): string => "#" + format(r) + format(g) + format(b); + +export const rgbToHsv = ({ r, g, b }: RGB): HSV => { + const max = Math.max(r, g, b); + const delta = max - Math.min(r, g, b); + + // prettier-ignore + const hh = delta + ? max === r + ? (g - b) / delta + : max === g + ? 2 + (b - r) / delta + : 4 + (r - g) / delta + : 0; + + return { + h: Math.round(60 * (hh < 0 ? hh + 6 : hh)), + s: Math.round(max ? (delta / max) * 100 : 0), + v: Math.round((max / 255) * 100), + }; +}; diff --git a/src/utils/equalHex.ts b/src/utils/equalHex.ts index 4cf573d5..2f145c82 100644 --- a/src/utils/equalHex.ts +++ b/src/utils/equalHex.ts @@ -1,4 +1,4 @@ -import hexToRgb from "./hexToRgb"; +import { hexToRgb } from "./conversions"; import equalColorObjects from "./equalColorObjects"; const equalHex = (first: string, second: string): boolean => { diff --git a/src/utils/hexToHsv.ts b/src/utils/hexToHsv.ts deleted file mode 100644 index aa143123..00000000 --- a/src/utils/hexToHsv.ts +++ /dev/null @@ -1,7 +0,0 @@ -import hexToRgb from "./hexToRgb"; -import rgbToHsv from "./rgbToHsv"; -import { HSV } from "../types"; - -const hexToHsv = (hex: string): HSV => rgbToHsv(hexToRgb(hex)); - -export default hexToHsv; diff --git a/src/utils/hexToRgb.ts b/src/utils/hexToRgb.ts deleted file mode 100644 index 241da32b..00000000 --- a/src/utils/hexToRgb.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { RGB } from "../types"; - -const hexToRgb = (hex: string): RGB => { - if (hex[0] === "#") hex = hex.substr(1); - - if (hex.length < 6) { - return { - r: parseInt(hex[0] + hex[0], 16), - g: parseInt(hex[1] + hex[1], 16), - b: parseInt(hex[2] + hex[2], 16), - }; - } - - return { - r: parseInt(hex.substr(0, 2), 16), - g: parseInt(hex.substr(2, 2), 16), - b: parseInt(hex.substr(4, 2), 16), - }; -}; - -export default hexToRgb; diff --git a/src/utils/hslStringToHsv.ts b/src/utils/hslStringToHsv.ts deleted file mode 100644 index 7267719e..00000000 --- a/src/utils/hslStringToHsv.ts +++ /dev/null @@ -1,16 +0,0 @@ -import hslToHsv from "./hslToHsv"; -import { HSV } from "../types"; - -const matcher = /hsl\((\d+(?:\.\d+)*),\s*(\d+(?:\.\d+)*)%?,\s*(\d+(?:\.\d+)*)%?\)/; - -const hslStringToHsv = (hslString: string): HSV => { - const match = matcher.exec(hslString); - - return hslToHsv({ - h: Number(match ? match : [1]), - s: Number(match ? match : [2]), - l: Number(match ? match : [3]), - }); -}; - -export default hslStringToHsv; diff --git a/src/utils/hslToHsv.ts b/src/utils/hslToHsv.ts deleted file mode 100644 index 66a8c9a3..00000000 --- a/src/utils/hslToHsv.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HSL, HSV } from "../types"; - -const hslToHsv = ({ h, s, l }: HSL): HSV => { - s *= (l < 50 ? l : 100 - l) / 100; - - return { - h: h, - s: s > 0 ? ((2 * s) / (l + s)) * 100 : 0, - v: l + s, - }; -}; - -export default hslToHsv; diff --git a/src/utils/hsvToHex.ts b/src/utils/hsvToHex.ts deleted file mode 100644 index 84be0295..00000000 --- a/src/utils/hsvToHex.ts +++ /dev/null @@ -1,7 +0,0 @@ -import rgbToHex from "./rgbToHex"; -import hsvToRgb from "./hsvToRgb"; -import { HSV } from "../types"; - -const hsvToHex = (hsv: HSV): string => rgbToHex(hsvToRgb(hsv)); - -export default hsvToHex; diff --git a/src/utils/hsvToHsl.ts b/src/utils/hsvToHsl.ts deleted file mode 100644 index f2c1c5a8..00000000 --- a/src/utils/hsvToHsl.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HSL, HSV } from "../types"; - -const hsvToHsl = ({ h, s, v }: HSV): HSL => { - const hh = ((200 - s) * v) / 100; - - return { - h: h, - s: hh > 0 && hh < 200 ? ((s * v) / 100 / (hh <= 100 ? hh : 200 - hh)) * 100 : 0, - l: hh / 2, - }; -}; - -export default hsvToHsl; diff --git a/src/utils/hsvToHslString.ts b/src/utils/hsvToHslString.ts deleted file mode 100644 index a008a2e5..00000000 --- a/src/utils/hsvToHslString.ts +++ /dev/null @@ -1,9 +0,0 @@ -import hsvToHsl from "./hsvToHsl"; -import { HSV } from "../types"; - -const hsvToHslString = (hsv: HSV): string => { - const { h, s, l } = hsvToHsl(hsv); - return `hsl(${h}, ${s}%, ${l}%)`; -}; - -export default hsvToHslString; diff --git a/src/utils/hsvToRgb.ts b/src/utils/hsvToRgb.ts deleted file mode 100644 index 621a483b..00000000 --- a/src/utils/hsvToRgb.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { HSV, RGB } from "../types"; - -const hsvToRgb = ({ h, s, v }: HSV): RGB => { - h = (h / 360) * 6; - s = s / 100; - v = v / 100; - - const hh = Math.floor(h), - b = v * (1 - s), - c = v * (1 - (h - hh) * s), - d = v * (1 - (1 - h + hh) * s), - module = hh % 6; - - return { - r: Math.round([v, c, b, b, d, v][module] * 255), - g: Math.round([d, v, v, c, b, b][module] * 255), - b: Math.round([b, b, d, v, v, c][module] * 255), - }; -}; - -export default hsvToRgb; diff --git a/src/utils/hsvToRgbString.ts b/src/utils/hsvToRgbString.ts deleted file mode 100644 index 91913e52..00000000 --- a/src/utils/hsvToRgbString.ts +++ /dev/null @@ -1,9 +0,0 @@ -import hsvToRgb from "./hsvToRgb"; -import { HSV } from "../types"; - -const hsvToRgbString = (hsv: HSV): string => { - const { r, g, b } = hsvToRgb(hsv); - return `rgb(${r}, ${g}, ${b})`; -}; - -export default hsvToRgbString; diff --git a/src/utils/rgbStringToHsv.ts b/src/utils/rgbStringToHsv.ts deleted file mode 100644 index a226d128..00000000 --- a/src/utils/rgbStringToHsv.ts +++ /dev/null @@ -1,16 +0,0 @@ -import rgbToHsv from "./rgbToHsv"; -import { HSV } from "../types"; - -const matcher = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/; - -const rgbStringToHsv = (string: string): HSV => { - const match = matcher.exec(string); - - return rgbToHsv({ - r: Number(match ? match : [1]), - g: Number(match ? match : [2]), - b: Number(match ? match : [3]), - }); -}; - -export default rgbStringToHsv; diff --git a/src/utils/rgbToHex.ts b/src/utils/rgbToHex.ts deleted file mode 100644 index 97f6b6f6..00000000 --- a/src/utils/rgbToHex.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RGB } from "../types"; - -const format = (number: number) => { - const hex = number.toString(16); - return hex.length < 2 ? "0" + hex : hex; -}; - -const rgbToHex = ({ r, g, b }: RGB): string => "#" + format(r) + format(g) + format(b); - -export default rgbToHex; diff --git a/src/utils/rgbToHsv.ts b/src/utils/rgbToHsv.ts deleted file mode 100644 index 30d8328b..00000000 --- a/src/utils/rgbToHsv.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { HSV, RGB } from "../types"; - -const rgbToHsv = ({ r, g, b }: RGB): HSV => { - const max = Math.max(r, g, b); - const delta = max - Math.min(r, g, b); - - const hh = delta - ? max === r - ? (g - b) / delta - : max === g - ? 2 + (b - r) / delta - : 4 + (r - g) / delta - : 0; - - return { - h: Math.round(60 * (hh < 0 ? hh + 6 : hh)), - s: Math.round(max ? (delta / max) * 100 : 0), - v: Math.round((max / 255) * 100), - }; -}; - -export default rgbToHsv; diff --git a/tsconfig.json b/tsconfig.json index 6ee17cbf..0f112621 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ "noImplicitAny": true, "outDir": "dist", "declaration": true, - "resolveJsonModule": true, "strict": true }, "include": ["src", "test"] From 0248b2b6dac1892e518f77b02224d107f8991548 Mon Sep 17 00:00:00 2001 From: Ryan Christian <33403762+RyanChristian4427@users.noreply.github.com> Date: Sun, 23 Aug 2020 05:09:31 +0100 Subject: [PATCH 05/29] fix(interactive): Hasty typing fix broke Interactive --- src/components/Interactive.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Interactive.tsx b/src/components/Interactive.tsx index ca55722a..72c498f7 100644 --- a/src/components/Interactive.tsx +++ b/src/components/Interactive.tsx @@ -58,7 +58,9 @@ const Interactive = ({ onMove, children }: Props) => { useLayoutEffect(() => { toggleDocumentEvents(isDragging); - if (isDragging) toggleDocumentEvents(false); + return () => { + isDragging && toggleDocumentEvents(false); + }; }, [isDragging, toggleDocumentEvents]); return ( From ab81376e8eff9f4bd7200327954bdf2e5bdd159e Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 14:55:46 +0100 Subject: [PATCH 06/29] fix(types): Correcting all props to be optional --- types/index.d.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index c089f4e8..2edf4c69 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,44 +1,44 @@ declare module "react-colorful" { import { FC } from "react"; - const ColorPicker: FC<{ className: string; color: string; onChange: (newColor: string) => void }>; + const ColorPicker: FC<{ className?: string; color?: string; onChange?: (newColor: string) => void }>; export = ColorPicker; } declare module "react-colorful/rgb" { import { FC } from "react"; type rgb = { r: number; g: number; b: number }; - const ColorPicker: FC<{ className: string; color: rgb; onChange: (newColor: rgb) => void }>; + const ColorPicker: FC<{ className?: string; color?: rgb; onChange?: (newColor: rgb) => void }>; export = ColorPicker; } declare module "react-colorful/rgbString" { import { FC } from "react"; - const ColorPicker: FC<{ className: string; color: string; onChange: (newColor: string) => void }>; + const ColorPicker: FC<{ className?: string; color?: string; onChange?: (newColor: string) => void }>; export = ColorPicker; } declare module "react-colorful/hsl" { import { FC } from "react"; type hsl = { h: number; s: number; l: number }; - const ColorPicker: FC<{ className: string; color: hsl; onChange: (newColor: hsl) => void }>; + const ColorPicker: FC<{ className?: string; color?: hsl; onChange?: (newColor: hsl) => void }>; export = ColorPicker; } declare module "react-colorful/hslString" { import { FC } from "react"; - const ColorPicker: FC<{ className: string; color: string; onChange: (newColor: string) => void }>; + const ColorPicker: FC<{ className?: string; color?: string; onChange?: (newColor: string) => void }>; export = ColorPicker; } declare module "react-colorful/hsv" { import { FC } from "react"; type hsv = { h: number; s: number; v: number }; - const ColorPicker: FC<{ className: string; color: hsv; onChange: (newColor: hsv) => void }>; + const ColorPicker: FC<{ className?: string; color?: hsv; onChange?: (newColor: hsv) => void }>; export = ColorPicker; } declare module "react-colorful/HexInput" { import { FC } from "react"; - const HexInput: FC<{ color: string; onChange: (newColor: string) => void }>; + const HexInput: FC<{ color?: string; onChange?: (newColor: string) => void }>; export = HexInput; } From d127b38ad934fb79b3f0f40fb0c1e0daec620b32 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 16:49:44 +0100 Subject: [PATCH 07/29] refactor: Working on PR comments, cleaning up types --- src/components/ColorPicker.tsx | 10 +++++----- src/components/HexInput.tsx | 2 +- src/hocs/withColorModel.tsx | 15 +++++++++++++++ src/packages/hex.tsx | 29 +++++++++++------------------ src/packages/hsl.tsx | 29 +++++++++++------------------ src/packages/hslString.tsx | 29 +++++++++++------------------ src/packages/hsv.tsx | 33 +++++++++++++-------------------- src/packages/rgb.tsx | 29 +++++++++++------------------ src/packages/rgbString.tsx | 29 +++++++++++------------------ src/types.ts | 17 ++++++++++------- src/utils/equalColorObjects.ts | 5 ++++- 11 files changed, 103 insertions(+), 124 deletions(-) create mode 100644 src/hocs/withColorModel.tsx diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index c32e86e9..e9dc8a9e 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -4,18 +4,18 @@ import Hue from "./Hue"; import Saturation from "./Saturation"; import styles from "../styles.css"; -import { ColorModel, Everything, HSV } from "../types"; +import { ColorModel, Color, HSV } from "../types"; import formatClassName from "../utils/formatClassName"; import equalColorObjects from "../utils/equalColorObjects"; interface Props { className: string; - colorModel: ColorModel; - color: Everything; - onChange: (newColor: any) => void; + colorModel: ColorModel; + color: Color; + onChange: (newColor: Color) => void; } -const ColorPicker = ({ +const ColorPicker: React.FC = ({ className, colorModel, color = colorModel.defaultColor, diff --git a/src/components/HexInput.tsx b/src/components/HexInput.tsx index 20753722..523ddc72 100644 --- a/src/components/HexInput.tsx +++ b/src/components/HexInput.tsx @@ -7,7 +7,7 @@ const escape = (hex: string) => hex.replace(/([^0-9A-F]+)/gi, ""); interface Props { color: string; - onChange: (newColor: any) => void; + onChange: (newColor: string) => void; } const HexInput = (props: Props) => { diff --git a/src/hocs/withColorModel.tsx b/src/hocs/withColorModel.tsx new file mode 100644 index 00000000..08fb7f25 --- /dev/null +++ b/src/hocs/withColorModel.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { ColorModel } from "../types"; + +const withColorModel = ( + Component: React.FC, + colorModel: ColorModel +): React.MemoExoticComponent => { + const ColorPicker = (props: any) => { + return ; + }; + + return React.memo(ColorPicker); +}; + +export default withColorModel; diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index fb430e70..4e93ab60 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -1,30 +1,23 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import { BaseComponentProps } from "../types"; +import withColorModel from "../hocs/withColorModel"; +import { ColorModel, ColorPickerBaseProps } from "../types"; import { hexToHsv, hsvToHex } from "../utils/conversions"; import equal from "../utils/equalHex"; -interface Props extends BaseComponentProps { - className: string; +interface Props extends ColorPickerBaseProps { color: string; onChange: (newColor: string) => void; } -const Hex: React.FC = (props) => { - return ( - - ); +const colorModel: ColorModel = { + defaultColor: { h: 0, s: 0, l: 0 }, + toHsv: hexToHsv, + fromHsv: hsvToHex, + equal, }; -export default React.memo(Hex); +const HexColorPicker: React.FC = withColorModel(ColorPicker, colorModel); + +export default HexColorPicker; diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index 82daa3eb..9c0ee87a 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -1,30 +1,23 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import { BaseComponentProps, HSL } from "../types"; +import withColorModel from "../hocs/withColorModel"; +import { ColorModel, ColorPickerBaseProps, HSL } from "../types"; import { hslToHsv, hsvToHsl } from "../utils/conversions"; import equal from "../utils/equalColorObjects"; -interface Props extends BaseComponentProps { - className: string; +interface Props extends ColorPickerBaseProps { color: HSL; onChange: (newColor: HSL) => void; } -const Hsl: React.FC = (props) => { - return ( - - ); +const colorModel: ColorModel = { + defaultColor: { h: 0, s: 0, l: 0 }, + toHsv: hslToHsv, + fromHsv: hsvToHsl, + equal, }; -export default React.memo(Hsl); +const HslColorPicker: React.FC = withColorModel(ColorPicker, colorModel); + +export default HslColorPicker; diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index 53e1a780..a917e525 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -1,30 +1,23 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import { BaseComponentProps } from "../types"; +import withColorModel from "../hocs/withColorModel"; +import { ColorModel, ColorPickerBaseProps } from "../types"; import { hslStringToHsv, hsvToHslString } from "../utils/conversions"; import equal from "../utils/equalColorObjects"; -interface Props extends BaseComponentProps { - className: string; +interface Props extends ColorPickerBaseProps { color: string; onChange: (newColor: string) => void; } -const HslString: React.FC = (props) => { - return ( - - ); +const colorModel: ColorModel = { + defaultColor: "hsl(0, 0%, 0%)", + toHsv: hslStringToHsv, + fromHsv: hsvToHslString, + equal, }; -export default React.memo(HslString); +const HslStringColorPicker: React.FC = withColorModel(ColorPicker, colorModel); + +export default HslStringColorPicker; diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index ccdd0ee4..d851c6c3 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -1,29 +1,22 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import { BaseComponentProps, HSV } from "../types"; +import withColorModel from "../hocs/withColorModel"; +import { ColorModel, ColorPickerBaseProps, HSV } from "../types"; import equal from "../utils/equalColorObjects"; -interface Props extends BaseComponentProps { - className: string; - color: HSV; - onChange: (newColor: HSV) => void; +interface Props extends ColorPickerBaseProps { + color: string; + onChange: (newColor: string) => void; } -const Hsv: React.FC = (props) => { - return ( - hsv, - fromHsv: (hsv) => hsv, - equal, - }} - color={props.color} - onChange={props.onChange} - /> - ); +const colorModel: ColorModel = { + defaultColor: { h: 0, s: 0, v: 0 }, + toHsv: (hsv) => hsv, + fromHsv: (hsv) => hsv, + equal, }; -export default React.memo(Hsv); +const HsvColorPicker: React.FC = withColorModel(ColorPicker, colorModel); + +export default HsvColorPicker; diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 04d4fddb..53174e60 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -1,30 +1,23 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import { BaseComponentProps, RGB } from "../types"; +import withColorModel from "../hocs/withColorModel"; +import { ColorModel, ColorPickerBaseProps, RGB } from "../types"; import { rgbToHsv, hsvToRgb } from "../utils/conversions"; import equal from "../utils/equalColorObjects"; -interface Props extends BaseComponentProps { - className: string; +interface Props extends ColorPickerBaseProps { color: RGB; onChange: (newColor: RGB) => void; } -const Rgb: React.FC = (props) => { - return ( - - ); +const colorModel: ColorModel = { + defaultColor: { r: 0, g: 0, b: 0 }, + toHsv: rgbToHsv, + fromHsv: hsvToRgb, + equal, }; -export default React.memo(Rgb); +const RgbColorPicker: React.FC = withColorModel(ColorPicker, colorModel); + +export default RgbColorPicker; diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 064b40b1..f2fcaa29 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -1,30 +1,23 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; +import withColorModel from "../hocs/withColorModel"; +import { ColorModel, ColorPickerBaseProps } from "../types"; import { rgbStringToHsv, hsvToRgbString } from "../utils/conversions"; import equal from "../utils/equalColorObjects"; -import { BaseComponentProps } from "../types"; -interface Props extends BaseComponentProps { - className: string; +interface Props extends ColorPickerBaseProps { color: string; onChange: (newColor: string) => void; } -const RgbString: React.FC = (props) => { - return ( - - ); +const colorModel: ColorModel = { + defaultColor: "rgb(0, 0, 0)", + toHsv: rgbStringToHsv, + fromHsv: hsvToRgbString, + equal, }; -export default React.memo(RgbString); +const RgbStringColorPicker: React.FC = withColorModel(ColorPicker, colorModel); + +export default RgbStringColorPicker; diff --git a/src/types.ts b/src/types.ts index 37f4254d..e580e2de 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,31 +2,34 @@ export interface RGB { r: number; g: number; b: number; + [key: string]: number; } export interface HSL { h: number; s: number; l: number; + [key: string]: number; } export interface HSV { h: number; s: number; v: number; + [key: string]: number; } -export type Everything = string | RGB | HSL | HSV; +export type Color = string | RGB | HSL | HSV; -export interface ColorModel { - defaultColor: Everything; - toHsv: (defaultColor: any) => HSV; - fromHsv: (hsv: HSV) => Everything; +export interface ColorModel { + defaultColor: Color; + toHsv: (defaultColor: T) => HSV; + fromHsv: (hsv: HSV) => T; equal: (first: any, second: any) => boolean; } -export interface BaseComponentProps { +export interface ColorPickerBaseProps { className: string; - color: any; + color: Color; onChange: (newColor: any) => void; } diff --git a/src/utils/equalColorObjects.ts b/src/utils/equalColorObjects.ts index 6a2a333b..482f7a9d 100644 --- a/src/utils/equalColorObjects.ts +++ b/src/utils/equalColorObjects.ts @@ -1,4 +1,7 @@ -const equalColorObjects = (first: any, second: any): boolean => { +const equalColorObjects = ( + first: Record, + second: Record +): boolean => { if (first === second) return true; for (const prop in first) { From e8d867c99f58af6a2b8d87c0e4963f83910004ea Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 17:21:00 +0100 Subject: [PATCH 08/29] refactor: Further cleaning `utils` directory --- src/components/ColorPicker.tsx | 2 +- src/components/HexInput.tsx | 2 +- src/components/Hue.tsx | 2 +- src/components/Saturation.tsx | 2 +- src/packages/hex.tsx | 6 +++--- src/packages/hsl.tsx | 6 +++--- src/packages/hslString.tsx | 6 +++--- src/packages/hsv.tsx | 4 ++-- src/packages/rgb.tsx | 6 +++--- src/packages/rgbString.tsx | 6 +++--- src/utils/compare.ts | 20 ++++++++++++++++++++ src/utils/{conversions.ts => convert.ts} | 0 src/utils/equalColorObjects.ts | 14 -------------- src/utils/equalHex.ts | 10 ---------- src/utils/validHex.ts | 6 ------ src/utils/validate.ts | 4 ++++ 16 files changed, 45 insertions(+), 51 deletions(-) create mode 100644 src/utils/compare.ts rename src/utils/{conversions.ts => convert.ts} (100%) delete mode 100644 src/utils/equalColorObjects.ts delete mode 100644 src/utils/equalHex.ts delete mode 100644 src/utils/validHex.ts create mode 100644 src/utils/validate.ts diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index e9dc8a9e..c15e4c2f 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -5,8 +5,8 @@ import Saturation from "./Saturation"; import styles from "../styles.css"; import { ColorModel, Color, HSV } from "../types"; +import { equalColorObjects } from "../utils/compare"; import formatClassName from "../utils/formatClassName"; -import equalColorObjects from "../utils/equalColorObjects"; interface Props { className: string; diff --git a/src/components/HexInput.tsx b/src/components/HexInput.tsx index 523ddc72..86fd51cd 100644 --- a/src/components/HexInput.tsx +++ b/src/components/HexInput.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useCallback } from "react"; -import validHex from "../utils/validHex"; +import { validHex } from "../utils/validate"; // Escapes all non-hexadecimal characters including "#" const escape = (hex: string) => hex.replace(/([^0-9A-F]+)/gi, ""); diff --git a/src/components/Hue.tsx b/src/components/Hue.tsx index 17d0f6a6..e0bf11a5 100644 --- a/src/components/Hue.tsx +++ b/src/components/Hue.tsx @@ -3,8 +3,8 @@ import React, { useCallback } from "react"; import Interactive from "./Interactive"; import styles from "../styles.css"; +import { hsvToHslString } from "../utils/convert"; import formatClassName from "../utils/formatClassName"; -import { hsvToHslString } from "../utils/conversions"; interface Props { hue: number; diff --git a/src/components/Saturation.tsx b/src/components/Saturation.tsx index 3945cc12..039dccfb 100644 --- a/src/components/Saturation.tsx +++ b/src/components/Saturation.tsx @@ -4,7 +4,7 @@ import Interactive from "./Interactive"; import styles from "../styles.css"; import { HSV } from "../types"; -import { hsvToHslString } from "../utils/conversions"; +import { hsvToHslString } from "../utils/convert"; import formatClassName from "../utils/formatClassName"; interface Props { diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index 4e93ab60..591ca2c9 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -3,8 +3,8 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; -import { hexToHsv, hsvToHex } from "../utils/conversions"; -import equal from "../utils/equalHex"; +import { equalHex } from "../utils/compare"; +import { hexToHsv, hsvToHex } from "../utils/convert"; interface Props extends ColorPickerBaseProps { color: string; @@ -15,7 +15,7 @@ const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, l: 0 }, toHsv: hexToHsv, fromHsv: hsvToHex, - equal, + equal: equalHex, }; const HexColorPicker: React.FC = withColorModel(ColorPicker, colorModel); diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index 9c0ee87a..a87bfdd2 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -3,8 +3,8 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, HSL } from "../types"; -import { hslToHsv, hsvToHsl } from "../utils/conversions"; -import equal from "../utils/equalColorObjects"; +import { equalColorObjects } from "../utils/compare"; +import { hslToHsv, hsvToHsl } from "../utils/convert"; interface Props extends ColorPickerBaseProps { color: HSL; @@ -15,7 +15,7 @@ const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, l: 0 }, toHsv: hslToHsv, fromHsv: hsvToHsl, - equal, + equal: equalColorObjects, }; const HslColorPicker: React.FC = withColorModel(ColorPicker, colorModel); diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index a917e525..1c9f4136 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -3,8 +3,8 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; -import { hslStringToHsv, hsvToHslString } from "../utils/conversions"; -import equal from "../utils/equalColorObjects"; +import { equalColorObjects } from "../utils/compare"; +import { hslStringToHsv, hsvToHslString } from "../utils/convert"; interface Props extends ColorPickerBaseProps { color: string; @@ -15,7 +15,7 @@ const colorModel: ColorModel = { defaultColor: "hsl(0, 0%, 0%)", toHsv: hslStringToHsv, fromHsv: hsvToHslString, - equal, + equal: equalColorObjects, }; const HslStringColorPicker: React.FC = withColorModel(ColorPicker, colorModel); diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index d851c6c3..6d4f943b 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -3,7 +3,7 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, HSV } from "../types"; -import equal from "../utils/equalColorObjects"; +import { equalColorObjects } from "../utils/compare"; interface Props extends ColorPickerBaseProps { color: string; @@ -14,7 +14,7 @@ const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, v: 0 }, toHsv: (hsv) => hsv, fromHsv: (hsv) => hsv, - equal, + equal: equalColorObjects, }; const HsvColorPicker: React.FC = withColorModel(ColorPicker, colorModel); diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 53174e60..14c4e8a9 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -3,8 +3,8 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, RGB } from "../types"; -import { rgbToHsv, hsvToRgb } from "../utils/conversions"; -import equal from "../utils/equalColorObjects"; +import { equalColorObjects } from "../utils/compare"; +import { rgbToHsv, hsvToRgb } from "../utils/convert"; interface Props extends ColorPickerBaseProps { color: RGB; @@ -15,7 +15,7 @@ const colorModel: ColorModel = { defaultColor: { r: 0, g: 0, b: 0 }, toHsv: rgbToHsv, fromHsv: hsvToRgb, - equal, + equal: equalColorObjects, }; const RgbColorPicker: React.FC = withColorModel(ColorPicker, colorModel); diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index f2fcaa29..4524acdc 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -3,8 +3,8 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; -import { rgbStringToHsv, hsvToRgbString } from "../utils/conversions"; -import equal from "../utils/equalColorObjects"; +import { equalColorObjects } from "../utils/compare"; +import { rgbStringToHsv, hsvToRgbString } from "../utils/convert"; interface Props extends ColorPickerBaseProps { color: string; @@ -15,7 +15,7 @@ const colorModel: ColorModel = { defaultColor: "rgb(0, 0, 0)", toHsv: rgbStringToHsv, fromHsv: hsvToRgbString, - equal, + equal: equalColorObjects, }; const RgbStringColorPicker: React.FC = withColorModel(ColorPicker, colorModel); diff --git a/src/utils/compare.ts b/src/utils/compare.ts new file mode 100644 index 00000000..d22c5839 --- /dev/null +++ b/src/utils/compare.ts @@ -0,0 +1,20 @@ +import { hexToRgb } from "./convert"; + +export const equalColorObjects = ( + first: Record, + second: Record +): boolean => { + if (first === second) return true; + + for (const prop in first) { + if (first[prop] !== second[prop]) return false; + } + + return true; +}; + +export const equalHex = (first: string, second: string): boolean => { + if (first.toLowerCase() === second.toLowerCase()) return true; + + return equalColorObjects(hexToRgb(first), hexToRgb(second)); +}; diff --git a/src/utils/conversions.ts b/src/utils/convert.ts similarity index 100% rename from src/utils/conversions.ts rename to src/utils/convert.ts diff --git a/src/utils/equalColorObjects.ts b/src/utils/equalColorObjects.ts deleted file mode 100644 index 482f7a9d..00000000 --- a/src/utils/equalColorObjects.ts +++ /dev/null @@ -1,14 +0,0 @@ -const equalColorObjects = ( - first: Record, - second: Record -): boolean => { - if (first === second) return true; - - for (const prop in first) { - if (first[prop] !== second[prop]) return false; - } - - return true; -}; - -export default equalColorObjects; diff --git a/src/utils/equalHex.ts b/src/utils/equalHex.ts deleted file mode 100644 index 2f145c82..00000000 --- a/src/utils/equalHex.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { hexToRgb } from "./conversions"; -import equalColorObjects from "./equalColorObjects"; - -const equalHex = (first: string, second: string): boolean => { - if (first.toLowerCase() === second.toLowerCase()) return true; - - return equalColorObjects(hexToRgb(first), hexToRgb(second)); -}; - -export default equalHex; diff --git a/src/utils/validHex.ts b/src/utils/validHex.ts deleted file mode 100644 index 299a11cc..00000000 --- a/src/utils/validHex.ts +++ /dev/null @@ -1,6 +0,0 @@ -const hex3 = /^#?[0-9A-F]{3}$/i; -const hex6 = /^#?[0-9A-F]{6}$/i; - -const validHex = (color: string): boolean => hex6.test(color) || hex3.test(color); - -export default validHex; diff --git a/src/utils/validate.ts b/src/utils/validate.ts new file mode 100644 index 00000000..eeb69098 --- /dev/null +++ b/src/utils/validate.ts @@ -0,0 +1,4 @@ +const hex3 = /^#?[0-9A-F]{3}$/i; +const hex6 = /^#?[0-9A-F]{6}$/i; + +export const validHex = (color: string): boolean => hex6.test(color) || hex3.test(color); From 115629c332e4cc8f22ceacbd0e7efb9b2b9b98be Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 17:36:39 +0100 Subject: [PATCH 09/29] fix: Correcting bad IDE suggestion to aviod null --- src/utils/convert.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils/convert.ts b/src/utils/convert.ts index 2e00518e..6043e4e0 100644 --- a/src/utils/convert.ts +++ b/src/utils/convert.ts @@ -25,9 +25,9 @@ export const hslStringToHsv = (hslString: string): HSV => { const match = matcher.exec(hslString); return hslToHsv({ - h: Number(match ? match : [1]), - s: Number(match ? match : [2]), - l: Number(match ? match : [3]), + h: Number(match ? match[1] : 0), + s: Number(match ? match[2] : 0), + l: Number(match ? match[3] : 0), }); }; @@ -86,9 +86,9 @@ export const rgbStringToHsv = (rgbString: string): HSV => { const match = matcher.exec(rgbString); return rgbToHsv({ - r: Number(match ? match : [1]), - g: Number(match ? match : [2]), - b: Number(match ? match : [3]), + r: Number(match ? match[1] : 0), + g: Number(match ? match[2] : 0), + b: Number(match ? match[3] : 0), }); }; From e7afe164efb450f29f90e08dc404fb2a05142053 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 17:37:05 +0100 Subject: [PATCH 10/29] test(util): Update util tests with correct import paths --- package.json | 4 +++- tests/utils.test.js | 21 ++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 0561ac4b..39a49a79 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,8 @@ "jest": { "verbose": true, "transform": { - "\\.js$": "jest-esm-jsx-transform" + "\\.js$": "jest-esm-jsx-transform", + "^.+\\.tsx?$": "ts-jest" }, "moduleNameMapper": { "\\.css$": "identity-obj-proxy" @@ -117,6 +118,7 @@ "react": "^16.8.0", "react-dom": "^16.8.0", "size-limit": "^4.5.5", + "ts-jest": "^26.2.0", "typescript": "^4.0.2", "use-throttled-effect": "0.0.7" }, diff --git a/tests/utils.test.js b/tests/utils.test.js index ce052709..873370ca 100644 --- a/tests/utils.test.js +++ b/tests/utils.test.js @@ -1,22 +1,17 @@ // HEX -import hexToHsv from "../src/utils/hexToHsv"; -import hsvToHex from "../src/utils/hsvToHex"; -import equalHex from "../src/utils/equalHex"; -import validHex from "../src/utils/validHex"; +import { hexToHsv, hsvToHex } from "../src/utils/convert"; +import { equalHex } from "../src/utils/compare"; +import { validHex } from "../src/utils/validate"; // HSL -import hsvToHsl from "../src/utils/hsvToHsl"; -import hslToHsv from "../src/utils/hslToHsv"; +import { hsvToHsl, hslToHsv } from "../src/utils/convert"; // HSL string -import hsvToHslString from "../src/utils/hsvToHslString"; -import hslStringToHsv from "../src/utils/hslStringToHsv"; +import { hsvToHslString, hslStringToHsv } from "../src/utils/convert"; // RGB -import hsvToRgb from "../src/utils/hsvToRgb"; -import rgbToHsv from "../src/utils/rgbToHsv"; +import { hsvToRgb, rgbToHsv } from "../src/utils/convert"; // RGB string -import hsvToRgbString from "../src/utils/hsvToRgbString"; -import rgbStringToHsv from "../src/utils/rgbStringToHsv"; +import { hsvToRgbString, rgbStringToHsv } from "../src/utils/convert"; // Rest -import equalColorObjects from "../src/utils/equalColorObjects"; +import { equalColorObjects } from "../src/utils/compare"; import formatClassName from "../src/utils/formatClassName"; it("Converts HEX to HSV", () => { From 971276b369d061fe8a44e291f29c754a3bd44aaa Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 17:39:44 +0100 Subject: [PATCH 11/29] fix: Resolving issue with incorrect Hex default color --- src/packages/hex.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index 591ca2c9..00dc331c 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -12,7 +12,7 @@ interface Props extends ColorPickerBaseProps { } const colorModel: ColorModel = { - defaultColor: { h: 0, s: 0, l: 0 }, + defaultColor: "000", toHsv: hexToHsv, fromHsv: hsvToHex, equal: equalHex, From 42bd359d90f6d7cb16eab815d264d5dd10592cea Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 17:48:27 +0100 Subject: [PATCH 12/29] refactor(deps): Downgrading TS version to stay within tooling range --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 39a49a79..77400159 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "react-dom": "^16.8.0", "size-limit": "^4.5.5", "ts-jest": "^26.2.0", - "typescript": "^4.0.2", + "typescript": "^3.9.7", "use-throttled-effect": "0.0.7" }, "dependencies": {} From 459d7dd59d9004f82fdf6926ee5d4acb0cba0f46 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 17:48:49 +0100 Subject: [PATCH 13/29] fix: Ensuring all components' props are optional --- src/packages/hex.tsx | 2 +- src/packages/hsl.tsx | 2 +- src/packages/hslString.tsx | 2 +- src/packages/hsv.tsx | 2 +- src/packages/rgb.tsx | 2 +- src/packages/rgbString.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index 00dc331c..34d24017 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -18,6 +18,6 @@ const colorModel: ColorModel = { equal: equalHex, }; -const HexColorPicker: React.FC = withColorModel(ColorPicker, colorModel); +const HexColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); export default HexColorPicker; diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index a87bfdd2..21cba404 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -18,6 +18,6 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HslColorPicker: React.FC = withColorModel(ColorPicker, colorModel); +const HslColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); export default HslColorPicker; diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index 1c9f4136..8c1df9ba 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -18,6 +18,6 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HslStringColorPicker: React.FC = withColorModel(ColorPicker, colorModel); +const HslStringColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); export default HslStringColorPicker; diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index 6d4f943b..71b37f0f 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -17,6 +17,6 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HsvColorPicker: React.FC = withColorModel(ColorPicker, colorModel); +const HsvColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); export default HsvColorPicker; diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 14c4e8a9..2f26f596 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -18,6 +18,6 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const RgbColorPicker: React.FC = withColorModel(ColorPicker, colorModel); +const RgbColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); export default RgbColorPicker; diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 4524acdc..eedc819e 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -18,6 +18,6 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const RgbStringColorPicker: React.FC = withColorModel(ColorPicker, colorModel); +const RgbStringColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); export default RgbStringColorPicker; From 717d0679dee5958e8a992faab30ebd053f404289 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sun, 23 Aug 2020 22:14:13 +0100 Subject: [PATCH 14/29] refactor(types): Solidified more of the types, some still left to do --- src/components/ColorPicker.tsx | 8 ++++---- src/components/Interactive.tsx | 12 +++++++++--- src/hocs/withColorModel.tsx | 7 ++++--- src/packages/hex.tsx | 3 +-- src/packages/hsl.tsx | 3 +-- src/packages/hslString.tsx | 3 +-- src/packages/hsv.tsx | 3 +-- src/packages/rgb.tsx | 3 +-- src/packages/rgbString.tsx | 3 +-- src/types.ts | 10 +++++----- 10 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index c15e4c2f..3386032f 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -4,15 +4,15 @@ import Hue from "./Hue"; import Saturation from "./Saturation"; import styles from "../styles.css"; -import { ColorModel, Color, HSV } from "../types"; +import { ColorModel, AnyColor, HSV } from "../types"; import { equalColorObjects } from "../utils/compare"; import formatClassName from "../utils/formatClassName"; interface Props { className: string; - colorModel: ColorModel; - color: Color; - onChange: (newColor: Color) => void; + colorModel: ColorModel; + color: AnyColor; + onChange: (newColor: AnyColor) => void; } const ColorPicker: React.FC = ({ diff --git a/src/components/Interactive.tsx b/src/components/Interactive.tsx index 72c498f7..34d20005 100644 --- a/src/components/Interactive.tsx +++ b/src/components/Interactive.tsx @@ -6,8 +6,13 @@ import styles from "../styles.css"; // Use ternary operator instead of `Math.min(Math.max(0, number), 1)` to save few bytes const limit = (number: number) => (number > 1 ? 1 : number < 0 ? 0 : number); +interface Interaction { + left: number; + top: number; +} + interface Props { - onMove: (interaction: any) => void; + onMove: (interaction: Interaction) => void; children: React.ReactNode; } @@ -16,8 +21,9 @@ const Interactive = ({ onMove, children }: Props) => { const [isDragging, setDragging] = useState(false); const getRelativePosition = useCallback((event) => { - if (!container.current) return; - const rect = container.current.getBoundingClientRect(); + // This should be okay. This is only called onMove, and for it to be moved it must actually exist. + // I won't suppress the ESLint warning though, as it should probably be something to be aware of. + const rect = container.current!.getBoundingClientRect(); const pointer = typeof event.pageX === "number" ? event : event.touches[0]; return { diff --git a/src/hocs/withColorModel.tsx b/src/hocs/withColorModel.tsx index 08fb7f25..bcc005ba 100644 --- a/src/hocs/withColorModel.tsx +++ b/src/hocs/withColorModel.tsx @@ -1,11 +1,12 @@ import React from "react"; -import { ColorModel } from "../types"; + +import { ColorModel, ColorPickerBaseProps } from "../types"; const withColorModel = ( Component: React.FC, colorModel: ColorModel -): React.MemoExoticComponent => { - const ColorPicker = (props: any) => { +): React.NamedExoticComponent => { + const ColorPicker = (props: ColorPickerBaseProps) => { return ; }; diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index 34d24017..dcdf70cf 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -6,9 +6,8 @@ import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalHex } from "../utils/compare"; import { hexToHsv, hsvToHex } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { +interface Props extends ColorPickerBaseProps { color: string; - onChange: (newColor: string) => void; } const colorModel: ColorModel = { diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index 21cba404..38385c02 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -6,9 +6,8 @@ import { ColorModel, ColorPickerBaseProps, HSL } from "../types"; import { equalColorObjects } from "../utils/compare"; import { hslToHsv, hsvToHsl } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { +interface Props extends ColorPickerBaseProps { color: HSL; - onChange: (newColor: HSL) => void; } const colorModel: ColorModel = { diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index 8c1df9ba..1fd5d89f 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -6,9 +6,8 @@ import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalColorObjects } from "../utils/compare"; import { hslStringToHsv, hsvToHslString } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { +interface Props extends ColorPickerBaseProps { color: string; - onChange: (newColor: string) => void; } const colorModel: ColorModel = { diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index 71b37f0f..aaf53d94 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -5,9 +5,8 @@ import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, HSV } from "../types"; import { equalColorObjects } from "../utils/compare"; -interface Props extends ColorPickerBaseProps { +interface Props extends ColorPickerBaseProps { color: string; - onChange: (newColor: string) => void; } const colorModel: ColorModel = { diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 2f26f596..29ab744b 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -6,9 +6,8 @@ import { ColorModel, ColorPickerBaseProps, RGB } from "../types"; import { equalColorObjects } from "../utils/compare"; import { rgbToHsv, hsvToRgb } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { +interface Props extends ColorPickerBaseProps { color: RGB; - onChange: (newColor: RGB) => void; } const colorModel: ColorModel = { diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index eedc819e..48e39fc8 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -6,9 +6,8 @@ import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalColorObjects } from "../utils/compare"; import { rgbStringToHsv, hsvToRgbString } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { +interface Props extends ColorPickerBaseProps { color: string; - onChange: (newColor: string) => void; } const colorModel: ColorModel = { diff --git a/src/types.ts b/src/types.ts index e580e2de..8ea0530f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,17 +19,17 @@ export interface HSV { [key: string]: number; } -export type Color = string | RGB | HSL | HSV; +export type AnyColor = string | RGB | HSL | HSV; export interface ColorModel { - defaultColor: Color; + defaultColor: AnyColor; toHsv: (defaultColor: T) => HSV; fromHsv: (hsv: HSV) => T; equal: (first: any, second: any) => boolean; } -export interface ColorPickerBaseProps { +export interface ColorPickerBaseProps { className: string; - color: Color; - onChange: (newColor: any) => void; + color: T; + onChange: (newColor: T) => void; } From 250edf4fe61919bce31c4aac5219779594772014 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 01:55:44 +0100 Subject: [PATCH 15/29] refactor: Reworked build system --- .gitignore | 9 -------- HexInput/package.json | 14 ++++++++++++ build-packages.js | 49 ------------------------------------------ hsl/package.json | 14 ++++++++++++ hslString/package.json | 14 ++++++++++++ hsv/package.json | 14 ++++++++++++ package.json | 11 ++++++++-- rgb/package.json | 14 ++++++++++++ rgbString/package.json | 14 ++++++++++++ 9 files changed, 93 insertions(+), 60 deletions(-) create mode 100644 HexInput/package.json delete mode 100644 build-packages.js create mode 100644 hsl/package.json create mode 100644 hslString/package.json create mode 100644 hsv/package.json create mode 100644 rgb/package.json create mode 100644 rgbString/package.json diff --git a/.gitignore b/.gitignore index f17d2b18..0512f440 100644 --- a/.gitignore +++ b/.gitignore @@ -14,15 +14,6 @@ node_modules/ .cache dist/ -# packages -/hex -/hsl -/hslString -/hsv -/rgb -/rgbString -/HexInput - # OSX .DS_Store .LSOverride \ No newline at end of file diff --git a/HexInput/package.json b/HexInput/package.json new file mode 100644 index 00000000..3dba01c8 --- /dev/null +++ b/HexInput/package.json @@ -0,0 +1,14 @@ +{ + "name": "react-colorful-hex-input", + "private": true, + "source": "../src/packages/HexInput.js", + "main": "dist/index.js", + "module": "dist/index.module.js", + "esmodule": "dist/index.esmodule.js", + "umd:main": "dist/index.umd.js", + "types": "../types/index.d.ts", + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } +} diff --git a/build-packages.js b/build-packages.js deleted file mode 100644 index 9424a78e..00000000 --- a/build-packages.js +++ /dev/null @@ -1,49 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const del = require("del"); -const util = require("util"); - -// Convert NodeJS methods to promises in order to use them with `await` statement -const exec = util.promisify(require("child_process").exec); -const writeFile = util.promisify(fs.writeFile); - -// Read available package sources from the dir -const entryDirPath = path.join(__dirname, "src/packages"); - -fs.readdir(entryDirPath, async (e, files) => { - console.log(`⚙️ Building ${files.length} packages...`); - - for (let file of files) { - const { name } = path.parse(file); - const isMainPackage = name === "hex"; - const filePath = path.join(entryDirPath, file); - const outputDirPath = path.join(__dirname, isMainPackage ? "dist" : name); - const manifestPath = path.join(outputDirPath, `package.json`); - const bundlerPath = path.join(__dirname, "node_modules/.bin/microbundle"); - - // Delete the previous package version if exists - await del(outputDirPath); - - // Run microbundle - const { stdout } = await exec( - `${bundlerPath} --entry ${filePath} --output ${outputDirPath}/index.js --name react-colorful-${name} --css-modules true --jsx React.createElement` - ); - console.log(stdout); - - if (!isMainPackage) { - // Create `package.json` - var manifestCode = JSON.stringify({ - name: `react-colorful-${name}`, - private: true, - main: "index.js", - module: "index.module.js", - esmodule: "index.esmodule.js", - types: "../types/index.d.ts" - }); - - await writeFile(manifestPath, manifestCode, "utf8"); - } - } - - console.log(`🎺 All packages are built`); -}); diff --git a/hsl/package.json b/hsl/package.json new file mode 100644 index 00000000..f3f94eaf --- /dev/null +++ b/hsl/package.json @@ -0,0 +1,14 @@ +{ + "name": "react-colorful-hsl", + "private": true, + "source": "../src/packages/hsl.js", + "main": "dist/index.js", + "module": "dist/index.module.js", + "esmodule": "dist/index.esmodule.js", + "umd:main": "dist/index.umd.js", + "types": "../types/index.d.ts", + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } +} diff --git a/hslString/package.json b/hslString/package.json new file mode 100644 index 00000000..fa6f0eff --- /dev/null +++ b/hslString/package.json @@ -0,0 +1,14 @@ +{ + "name": "react-colorful-hsl-string", + "private": true, + "source": "../src/packages/hslString.js", + "main": "dist/index.js", + "module": "dist/index.module.js", + "esmodule": "dist/index.esmodule.js", + "umd:main": "dist/index.umd.js", + "types": "../types/index.d.ts", + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } +} diff --git a/hsv/package.json b/hsv/package.json new file mode 100644 index 00000000..f3db753c --- /dev/null +++ b/hsv/package.json @@ -0,0 +1,14 @@ +{ + "name": "react-colorful-hsv", + "private": true, + "source": "../src/packages/hsv.js", + "main": "dist/index.js", + "module": "dist/index.module.js", + "esmodule": "dist/index.esmodule.js", + "umd:main": "dist/index.umd.js", + "types": "../types/index.d.ts", + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } +} diff --git a/package.json b/package.json index 9a7e3174..974ab61c 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,14 @@ "lint": "eslint src/**/*.js demo/src/**/*.js", "size": "npm run build && size-limit", "test": "jest tests", - "build": "node ./build-packages.js", + "build": "npm-run-all --parallel build:*", + "build:submodule": "microbundle build --css-modules true --jsx React.createElement", + "build:hexInput": "npm run build:submodule -- --cwd HexInput", + "build:hsl": "npm run build:submodule -- --cwd hsl", + "build:hslString": "npm run build:submodule -- --cwd hslString", + "build:hsv": "npm run build:submodule -- --cwd hsv", + "build:rgb": "npm run build:submodule -- --cwd rgb", + "build:rgbString": "npm run build:submodule -- --cwd rgbString", "prepublishOnly": "npm run build", "start-demo": "parcel demo/src/index.html --out-dir demo/dist --open", "build-demo": "del-cli 'demo/dist/*' && parcel build demo/src/index.html --out-dir demo/dist --public-url /react-colorful/", @@ -96,7 +103,6 @@ "@size-limit/preset-small-lib": "^4.5.6", "@testing-library/react": "^10.4.8", "@types/react": "^16.9.46", - "del": "^5.1.0", "del-cli": "^3.0.1", "eslint": "^7.5.0", "eslint-config-prettier": "^6.11.0", @@ -108,6 +114,7 @@ "jest": "^26.3.0", "jest-esm-jsx-transform": "^1.0.0", "microbundle": "^0.12.3", + "npm-run-all": "^4.1.5", "parcel-bundler": "^1.12.4", "postcss-modules": "^3.2.0", "prettier": "2.0.5", diff --git a/rgb/package.json b/rgb/package.json new file mode 100644 index 00000000..8955c13b --- /dev/null +++ b/rgb/package.json @@ -0,0 +1,14 @@ +{ + "name": "react-colorful-rgb", + "private": true, + "source": "../src/packages/rgb.js", + "main": "dist/index.js", + "module": "dist/index.module.js", + "esmodule": "dist/index.esmodule.js", + "umd:main": "dist/index.umd.js", + "types": "../types/index.d.ts", + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } +} diff --git a/rgbString/package.json b/rgbString/package.json new file mode 100644 index 00000000..8a893e97 --- /dev/null +++ b/rgbString/package.json @@ -0,0 +1,14 @@ +{ + "name": "react-colorful-rgb-string", + "private": true, + "source": "../src/packages/rgbString.js", + "main": "dist/index.js", + "module": "dist/index.module.js", + "esmodule": "dist/index.esmodule.js", + "umd:main": "dist/index.umd.js", + "types": "../types/index.d.ts", + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } +} From 3572b5370a189e33303f9cd86123e1ba0621febc Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 02:32:11 +0100 Subject: [PATCH 16/29] fix: Resolving issues with size-limit paths --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 974ab61c..db275f30 100644 --- a/package.json +++ b/package.json @@ -31,27 +31,27 @@ "limit": "2 KB" }, { - "path": "rgb/index.module.js", + "path": "rgb/dist/index.module.js", "limit": "2 KB" }, { - "path": "rgbString/index.module.js", + "path": "rgbString/dist/index.module.js", "limit": "2 KB" }, { - "path": "hsl/index.module.js", + "path": "hsl/dist/index.module.js", "limit": "2 KB" }, { - "path": "hslString/index.module.js", + "path": "hslString/dist/index.module.js", "limit": "2 KB" }, { - "path": "hsv/index.js", + "path": "hsv/dist/index.module.js", "limit": "2 KB" }, { - "path": "HexInput/index.module.js", + "path": "HexInput/dist/index.module.js", "limit": "1 KB" } ], From 91218d7c434c298aa392828afab93c104dcb4107 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 05:01:18 +0100 Subject: [PATCH 17/29] refactor: `Any` Crusade 2: Electric Boogaloo --- src/components/Hue.tsx | 2 +- src/components/Saturation.tsx | 7 ++++--- src/packages/hslString.tsx | 4 ++-- src/packages/rgbString.tsx | 4 ++-- src/types.ts | 2 +- src/utils/compare.ts | 8 ++++++-- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/components/Hue.tsx b/src/components/Hue.tsx index e0bf11a5..3d5553c1 100644 --- a/src/components/Hue.tsx +++ b/src/components/Hue.tsx @@ -8,7 +8,7 @@ import formatClassName from "../utils/formatClassName"; interface Props { hue: number; - onChange: (newColor: any) => void; + onChange: (newHue: { h: number }) => void; } const Hue = ({ hue, onChange }: Props) => { diff --git a/src/components/Saturation.tsx b/src/components/Saturation.tsx index 039dccfb..7927d38d 100644 --- a/src/components/Saturation.tsx +++ b/src/components/Saturation.tsx @@ -3,13 +3,13 @@ import React, { useCallback } from "react"; import Interactive from "./Interactive"; import styles from "../styles.css"; -import { HSV } from "../types"; +import { AnyColor, HSV } from "../types"; import { hsvToHslString } from "../utils/convert"; import formatClassName from "../utils/formatClassName"; interface Props { hsv: HSV; - onChange: (newColor: any) => void; + onChange: (newColor: AnyColor) => void; } const Saturation = ({ hsv, onChange }: Props) => { @@ -17,11 +17,12 @@ const Saturation = ({ hsv, onChange }: Props) => { (interaction) => { // Saturation and brightness always fit into [0, 100] range onChange({ + h: hsv.h, s: interaction.left * 100, v: 100 - interaction.top * 100, }); }, - [onChange] + [hsv.h, onChange] ); const containerStyle = { diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index 1fd5d89f..0e575f5d 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -3,7 +3,7 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; -import { equalColorObjects } from "../utils/compare"; +import { equalColorString } from "../utils/compare"; import { hslStringToHsv, hsvToHslString } from "../utils/convert"; interface Props extends ColorPickerBaseProps { @@ -14,7 +14,7 @@ const colorModel: ColorModel = { defaultColor: "hsl(0, 0%, 0%)", toHsv: hslStringToHsv, fromHsv: hsvToHslString, - equal: equalColorObjects, + equal: equalColorString, }; const HslStringColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 48e39fc8..1604107e 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -3,7 +3,7 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; -import { equalColorObjects } from "../utils/compare"; +import { equalColorString } from "../utils/compare"; import { rgbStringToHsv, hsvToRgbString } from "../utils/convert"; interface Props extends ColorPickerBaseProps { @@ -14,7 +14,7 @@ const colorModel: ColorModel = { defaultColor: "rgb(0, 0, 0)", toHsv: rgbStringToHsv, fromHsv: hsvToRgbString, - equal: equalColorObjects, + equal: equalColorString, }; const RgbStringColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); diff --git a/src/types.ts b/src/types.ts index 8ea0530f..e7cae046 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,7 +25,7 @@ export interface ColorModel { defaultColor: AnyColor; toHsv: (defaultColor: T) => HSV; fromHsv: (hsv: HSV) => T; - equal: (first: any, second: any) => boolean; + equal: (first: T, second: T) => boolean; } export interface ColorPickerBaseProps { diff --git a/src/utils/compare.ts b/src/utils/compare.ts index d22c5839..03e976fa 100644 --- a/src/utils/compare.ts +++ b/src/utils/compare.ts @@ -1,8 +1,8 @@ import { hexToRgb } from "./convert"; export const equalColorObjects = ( - first: Record, - second: Record + first: Record, + second: Record ): boolean => { if (first === second) return true; @@ -13,6 +13,10 @@ export const equalColorObjects = ( return true; }; +export const equalColorString = (first: string, second: string): boolean => { + return first.replace(/\s/g, "") === second.replace(/\s/g, ""); +}; + export const equalHex = (first: string, second: string): boolean => { if (first.toLowerCase() === second.toLowerCase()) return true; From 0296be7e65dce302928617dedcb7c67dc4a7c1a9 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 05:01:48 +0100 Subject: [PATCH 18/29] style: Silencing TS lint return type warning in JS files --- .eslintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index b2e52374..7a6b94d9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -34,7 +34,8 @@ "*.js" ], "rules": { - "@typescript-eslint/no-var-requires": [0] + "@typescript-eslint/no-var-requires": [0], + "@typescript-eslint/explicit-module-boundary-types": [0] } } ] From 14eec5ed68a6750e6140e5216d29fa8bb8dbd67c Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 05:11:31 +0100 Subject: [PATCH 19/29] fix(types): Correcting built types paths in modules --- HexInput/package.json | 2 +- hsl/package.json | 2 +- hslString/package.json | 2 +- hsv/package.json | 2 +- package.json | 4 ++-- rgb/package.json | 2 +- rgbString/package.json | 2 +- src/index.ts | 2 -- tests/components.test.js | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 src/index.ts diff --git a/HexInput/package.json b/HexInput/package.json index 6f365e0e..385852fb 100644 --- a/HexInput/package.json +++ b/HexInput/package.json @@ -6,7 +6,7 @@ "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/HexInput.d.ts", "peerDependencies": { "react": "^16.8.0", "react-dom": "^16.8.0" diff --git a/hsl/package.json b/hsl/package.json index f8f11082..9eebfcbd 100644 --- a/hsl/package.json +++ b/hsl/package.json @@ -6,7 +6,7 @@ "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/hsl.d.ts", "peerDependencies": { "react": "^16.8.0", "react-dom": "^16.8.0" diff --git a/hslString/package.json b/hslString/package.json index df288a7b..39720926 100644 --- a/hslString/package.json +++ b/hslString/package.json @@ -6,7 +6,7 @@ "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/hslString.d.ts", "peerDependencies": { "react": "^16.8.0", "react-dom": "^16.8.0" diff --git a/hsv/package.json b/hsv/package.json index 0c612157..4d6f31c0 100644 --- a/hsv/package.json +++ b/hsv/package.json @@ -6,7 +6,7 @@ "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/hsv.d.ts", "peerDependencies": { "react": "^16.8.0", "react-dom": "^16.8.0" diff --git a/package.json b/package.json index c1c8cdaf..b12b49cb 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,12 @@ "name": "react-colorful", "version": "2.2.1", "description": "A tiny color picker component for modern React apps", - "source": "src/index.ts", + "source": "src/packages/hex.tsx", "main": "dist/index.js", "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/hex.d.ts", "scripts": { "lint": "eslint src/**/*.{ts,tsx} demo/src/**/*.js", "size": "npm run build && size-limit", diff --git a/rgb/package.json b/rgb/package.json index a09ef97c..ec6c4702 100644 --- a/rgb/package.json +++ b/rgb/package.json @@ -6,7 +6,7 @@ "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/rgb.d.ts", "peerDependencies": { "react": "^16.8.0", "react-dom": "^16.8.0" diff --git a/rgbString/package.json b/rgbString/package.json index 524e098e..b4ca6b67 100644 --- a/rgbString/package.json +++ b/rgbString/package.json @@ -6,7 +6,7 @@ "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/index.d.ts", + "types": "dist/packages/rgbString.d.ts", "peerDependencies": { "react": "^16.8.0", "react-dom": "^16.8.0" diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index a6446dee..00000000 --- a/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import HexColorPicker from "./packages/hex"; -export default HexColorPicker; diff --git a/tests/components.test.js b/tests/components.test.js index 84e723b9..ab3f7709 100644 --- a/tests/components.test.js +++ b/tests/components.test.js @@ -1,6 +1,6 @@ import React from "react"; import { render, cleanup, fireEvent, waitFor } from "@testing-library/react"; -import ColorPicker from "../src/"; +import ColorPicker from "../src/packages/hex"; import HexInput from "../src/packages/HexInput"; afterEach(cleanup); From 581ae52ed63af1ad2b7905d915e1c028be4e0085 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 20:31:05 +0100 Subject: [PATCH 20/29] refactor(pr): Working on PR comments --- src/components/ColorPicker.tsx | 7 ++----- src/components/Hue.tsx | 4 ++-- src/components/Interactive.tsx | 2 +- src/components/Saturation.tsx | 7 +++---- src/packages/hex.tsx | 9 ++++----- src/packages/hsl.tsx | 9 ++++----- src/packages/hslString.tsx | 9 ++++----- src/packages/hsv.tsx | 9 ++++----- src/packages/rgb.tsx | 9 ++++----- src/packages/rgbString.tsx | 9 ++++----- src/types.ts | 2 +- src/utils/compare.ts | 7 +++---- 12 files changed, 36 insertions(+), 47 deletions(-) diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 3386032f..0300608e 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -4,15 +4,12 @@ import Hue from "./Hue"; import Saturation from "./Saturation"; import styles from "../styles.css"; -import { ColorModel, AnyColor, HSV } from "../types"; +import { ColorModel, AnyColor, HSV, ColorPickerBaseProps } from "../types"; import { equalColorObjects } from "../utils/compare"; import formatClassName from "../utils/formatClassName"; -interface Props { - className: string; +interface Props extends ColorPickerBaseProps { colorModel: ColorModel; - color: AnyColor; - onChange: (newColor: AnyColor) => void; } const ColorPicker: React.FC = ({ diff --git a/src/components/Hue.tsx b/src/components/Hue.tsx index 3d5553c1..36d9c418 100644 --- a/src/components/Hue.tsx +++ b/src/components/Hue.tsx @@ -1,6 +1,6 @@ import React, { useCallback } from "react"; -import Interactive from "./Interactive"; +import Interactive, { Interaction } from "./Interactive"; import styles from "../styles.css"; import { hsvToHslString } from "../utils/convert"; @@ -13,7 +13,7 @@ interface Props { const Hue = ({ hue, onChange }: Props) => { const handleMove = useCallback( - (interaction) => { + (interaction: Interaction) => { // Hue measured in degrees of the color circle ranging from 0 to 360 onChange({ h: 360 * interaction.left }); }, diff --git a/src/components/Interactive.tsx b/src/components/Interactive.tsx index 34d20005..99257be3 100644 --- a/src/components/Interactive.tsx +++ b/src/components/Interactive.tsx @@ -6,7 +6,7 @@ import styles from "../styles.css"; // Use ternary operator instead of `Math.min(Math.max(0, number), 1)` to save few bytes const limit = (number: number) => (number > 1 ? 1 : number < 0 ? 0 : number); -interface Interaction { +export interface Interaction { left: number; top: number; } diff --git a/src/components/Saturation.tsx b/src/components/Saturation.tsx index 7927d38d..52a35647 100644 --- a/src/components/Saturation.tsx +++ b/src/components/Saturation.tsx @@ -3,13 +3,13 @@ import React, { useCallback } from "react"; import Interactive from "./Interactive"; import styles from "../styles.css"; -import { AnyColor, HSV } from "../types"; +import { HSV } from "../types"; import { hsvToHslString } from "../utils/convert"; import formatClassName from "../utils/formatClassName"; interface Props { hsv: HSV; - onChange: (newColor: AnyColor) => void; + onChange: (newColor: { s: number; v: number }) => void; } const Saturation = ({ hsv, onChange }: Props) => { @@ -17,12 +17,11 @@ const Saturation = ({ hsv, onChange }: Props) => { (interaction) => { // Saturation and brightness always fit into [0, 100] range onChange({ - h: hsv.h, s: interaction.left * 100, v: 100 - interaction.top * 100, }); }, - [hsv.h, onChange] + [onChange] ); const containerStyle = { diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index dcdf70cf..5f3b1dbd 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -6,10 +6,6 @@ import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalHex } from "../utils/compare"; import { hexToHsv, hsvToHex } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { - color: string; -} - const colorModel: ColorModel = { defaultColor: "000", toHsv: hexToHsv, @@ -17,6 +13,9 @@ const colorModel: ColorModel = { equal: equalHex, }; -const HexColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); +const HexColorPicker: React.FC>> = withColorModel( + ColorPicker, + colorModel +); export default HexColorPicker; diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index 38385c02..d46c359f 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -6,10 +6,6 @@ import { ColorModel, ColorPickerBaseProps, HSL } from "../types"; import { equalColorObjects } from "../utils/compare"; import { hslToHsv, hsvToHsl } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { - color: HSL; -} - const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, l: 0 }, toHsv: hslToHsv, @@ -17,6 +13,9 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HslColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); +const HslColorPicker: React.FC>> = withColorModel( + ColorPicker, + colorModel +); export default HslColorPicker; diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index 0e575f5d..eb4272a2 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -6,10 +6,6 @@ import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalColorString } from "../utils/compare"; import { hslStringToHsv, hsvToHslString } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { - color: string; -} - const colorModel: ColorModel = { defaultColor: "hsl(0, 0%, 0%)", toHsv: hslStringToHsv, @@ -17,6 +13,9 @@ const colorModel: ColorModel = { equal: equalColorString, }; -const HslStringColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); +const HslStringColorPicker: React.FC>> = withColorModel( + ColorPicker, + colorModel +); export default HslStringColorPicker; diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index aaf53d94..879ea8c5 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -5,10 +5,6 @@ import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, HSV } from "../types"; import { equalColorObjects } from "../utils/compare"; -interface Props extends ColorPickerBaseProps { - color: string; -} - const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, v: 0 }, toHsv: (hsv) => hsv, @@ -16,6 +12,9 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HsvColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); +const HsvColorPicker: React.FC>> = withColorModel( + ColorPicker, + colorModel +); export default HsvColorPicker; diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 29ab744b..2dfd8b5f 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -6,10 +6,6 @@ import { ColorModel, ColorPickerBaseProps, RGB } from "../types"; import { equalColorObjects } from "../utils/compare"; import { rgbToHsv, hsvToRgb } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { - color: RGB; -} - const colorModel: ColorModel = { defaultColor: { r: 0, g: 0, b: 0 }, toHsv: rgbToHsv, @@ -17,6 +13,9 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const RgbColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); +const RgbColorPicker: React.FC>> = withColorModel( + ColorPicker, + colorModel +); export default RgbColorPicker; diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 1604107e..77228e21 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -6,10 +6,6 @@ import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalColorString } from "../utils/compare"; import { rgbStringToHsv, hsvToRgbString } from "../utils/convert"; -interface Props extends ColorPickerBaseProps { - color: string; -} - const colorModel: ColorModel = { defaultColor: "rgb(0, 0, 0)", toHsv: rgbStringToHsv, @@ -17,6 +13,9 @@ const colorModel: ColorModel = { equal: equalColorString, }; -const RgbStringColorPicker: React.FC> = withColorModel(ColorPicker, colorModel); +const RgbStringColorPicker: React.FC>> = withColorModel( + ColorPicker, + colorModel +); export default RgbStringColorPicker; diff --git a/src/types.ts b/src/types.ts index e7cae046..8da0ebe1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -22,7 +22,7 @@ export interface HSV { export type AnyColor = string | RGB | HSL | HSV; export interface ColorModel { - defaultColor: AnyColor; + defaultColor: T; toHsv: (defaultColor: T) => HSV; fromHsv: (hsv: HSV) => T; equal: (first: T, second: T) => boolean; diff --git a/src/utils/compare.ts b/src/utils/compare.ts index 03e976fa..8f9d77ac 100644 --- a/src/utils/compare.ts +++ b/src/utils/compare.ts @@ -1,9 +1,8 @@ import { hexToRgb } from "./convert"; -export const equalColorObjects = ( - first: Record, - second: Record -): boolean => { +import { HSL, HSV, RGB } from "../types"; + +export const equalColorObjects = (first: HSL | HSV | RGB, second: HSL | HSV | RGB): boolean => { if (first === second) return true; for (const prop in first) { From ba6864dead79c20ab7101702cfdbfd190ceaa408 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 21:21:25 +0100 Subject: [PATCH 21/29] fix: Making `HexInput`'s props optional --- src/components/HexInput.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/HexInput.tsx b/src/components/HexInput.tsx index 86fd51cd..03a03c97 100644 --- a/src/components/HexInput.tsx +++ b/src/components/HexInput.tsx @@ -10,8 +10,12 @@ interface Props { onChange: (newColor: string) => void; } -const HexInput = (props: Props) => { - const { color, onChange } = props; +const HexInput = (props: Partial) => { + const { color, onChange }: Props = { + color: "", + onChange: () => ({}), + ...props, + }; const [value, setValue] = useState(escape(color)); // Trigger `onChange` handler only if the input value is a valid HEX-color @@ -19,7 +23,7 @@ const HexInput = (props: Props) => { (e) => { const inputValue = escape(e.target.value); setValue(inputValue); - if (onChange && validHex(inputValue)) onChange("#" + inputValue); + if (validHex(inputValue)) onChange("#" + inputValue); }, [onChange] ); @@ -50,8 +54,4 @@ const HexInput = (props: Props) => { return React.createElement("input", inputProps); }; -HexInput.defaultProps = { - color: "", -}; - export default React.memo(HexInput); From 285dd5b6960f5c2a9bb159d4008550e98a7f90cc Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Aug 2020 22:27:33 +0100 Subject: [PATCH 22/29] misc(feedback): Need feedback on this behavior --- src/components/ColorPicker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 0300608e..935c2401 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -12,12 +12,12 @@ interface Props extends ColorPickerBaseProps { colorModel: ColorModel; } -const ColorPicker: React.FC = ({ +const ColorPicker = ({ className, colorModel, color = colorModel.defaultColor, onChange, -}: Props) => { +}: Props): JSX.Element => { // No matter which color model is used (HEX, RGB or HSL), // all internal calculations are based on HSV model const [hsv, updateHsv] = useState(() => colorModel.toHsv(color)); From 9a310e9e5295edef7d4638b27d6984305435cc7e Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 25 Aug 2020 21:13:29 +0100 Subject: [PATCH 23/29] refactor(types): Mostly finalized types --- src/components/ColorPicker.tsx | 12 ++++++------ src/hocs/withColorModel.tsx | 16 ---------------- src/packages/hex.tsx | 6 ++---- src/packages/hsl.tsx | 6 ++---- src/packages/hslString.tsx | 6 ++---- src/packages/hsv.tsx | 6 ++---- src/packages/rgb.tsx | 6 ++---- src/packages/rgbString.tsx | 6 ++---- src/types.ts | 6 +++--- 9 files changed, 21 insertions(+), 49 deletions(-) delete mode 100644 src/hocs/withColorModel.tsx diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 935c2401..c9070f3d 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -4,20 +4,20 @@ import Hue from "./Hue"; import Saturation from "./Saturation"; import styles from "../styles.css"; -import { ColorModel, AnyColor, HSV, ColorPickerBaseProps } from "../types"; +import { ColorModel, HSV, ColorPickerBaseProps, AnyColor } from "../types"; import { equalColorObjects } from "../utils/compare"; import formatClassName from "../utils/formatClassName"; -interface Props extends ColorPickerBaseProps { - colorModel: ColorModel; +interface Props extends ColorPickerBaseProps { + colorModel: ColorModel; } -const ColorPicker = ({ +const ColorPicker = ({ className, colorModel, color = colorModel.defaultColor, onChange, -}: Props): JSX.Element => { +}: Props) => { // No matter which color model is used (HEX, RGB or HSL), // all internal calculations are based on HSV model const [hsv, updateHsv] = useState(() => colorModel.toHsv(color)); @@ -62,4 +62,4 @@ const ColorPicker = ({ ); }; -export default ColorPicker; +export default React.memo(ColorPicker) as typeof ColorPicker; diff --git a/src/hocs/withColorModel.tsx b/src/hocs/withColorModel.tsx deleted file mode 100644 index bcc005ba..00000000 --- a/src/hocs/withColorModel.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; - -import { ColorModel, ColorPickerBaseProps } from "../types"; - -const withColorModel = ( - Component: React.FC, - colorModel: ColorModel -): React.NamedExoticComponent => { - const ColorPicker = (props: ColorPickerBaseProps) => { - return ; - }; - - return React.memo(ColorPicker); -}; - -export default withColorModel; diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index 5f3b1dbd..e458c7e1 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -1,7 +1,6 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalHex } from "../utils/compare"; import { hexToHsv, hsvToHex } from "../utils/convert"; @@ -13,9 +12,8 @@ const colorModel: ColorModel = { equal: equalHex, }; -const HexColorPicker: React.FC>> = withColorModel( - ColorPicker, - colorModel +const HexColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( + ); export default HexColorPicker; diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index d46c359f..fb5ba558 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -1,7 +1,6 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, HSL } from "../types"; import { equalColorObjects } from "../utils/compare"; import { hslToHsv, hsvToHsl } from "../utils/convert"; @@ -13,9 +12,8 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HslColorPicker: React.FC>> = withColorModel( - ColorPicker, - colorModel +const HslColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( + ); export default HslColorPicker; diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index eb4272a2..cfa6ff75 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -1,7 +1,6 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalColorString } from "../utils/compare"; import { hslStringToHsv, hsvToHslString } from "../utils/convert"; @@ -13,9 +12,8 @@ const colorModel: ColorModel = { equal: equalColorString, }; -const HslStringColorPicker: React.FC>> = withColorModel( - ColorPicker, - colorModel +const HslStringColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( + ); export default HslStringColorPicker; diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index 879ea8c5..b5c90a2a 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -1,7 +1,6 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, HSV } from "../types"; import { equalColorObjects } from "../utils/compare"; @@ -12,9 +11,8 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HsvColorPicker: React.FC>> = withColorModel( - ColorPicker, - colorModel +const HsvColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( + ); export default HsvColorPicker; diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index 2dfd8b5f..e64e8b42 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -1,7 +1,6 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps, RGB } from "../types"; import { equalColorObjects } from "../utils/compare"; import { rgbToHsv, hsvToRgb } from "../utils/convert"; @@ -13,9 +12,8 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const RgbColorPicker: React.FC>> = withColorModel( - ColorPicker, - colorModel +const RgbColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( + ); export default RgbColorPicker; diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 77228e21..81879d37 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -1,7 +1,6 @@ import React from "react"; import ColorPicker from "../components/ColorPicker"; -import withColorModel from "../hocs/withColorModel"; import { ColorModel, ColorPickerBaseProps } from "../types"; import { equalColorString } from "../utils/compare"; import { rgbStringToHsv, hsvToRgbString } from "../utils/convert"; @@ -13,9 +12,8 @@ const colorModel: ColorModel = { equal: equalColorString, }; -const RgbStringColorPicker: React.FC>> = withColorModel( - ColorPicker, - colorModel +const RgbStringColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( + ); export default RgbStringColorPicker; diff --git a/src/types.ts b/src/types.ts index 8da0ebe1..b6b822c7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,16 +19,16 @@ export interface HSV { [key: string]: number; } -export type AnyColor = string | RGB | HSL | HSV; +export type AnyColor = string | HSL | HSV | RGB; -export interface ColorModel { +export interface ColorModel { defaultColor: T; toHsv: (defaultColor: T) => HSV; fromHsv: (hsv: HSV) => T; equal: (first: T, second: T) => boolean; } -export interface ColorPickerBaseProps { +export interface ColorPickerBaseProps { className: string; color: T; onChange: (newColor: T) => void; From 0244e578ad2bd3f2b6a1acca28989b426de1900e Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 25 Aug 2020 21:50:30 +0100 Subject: [PATCH 24/29] refactor: Removing spread operator from HexInput --- src/components/HexInput.tsx | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/components/HexInput.tsx b/src/components/HexInput.tsx index 03a03c97..63e152f8 100644 --- a/src/components/HexInput.tsx +++ b/src/components/HexInput.tsx @@ -10,12 +10,7 @@ interface Props { onChange: (newColor: string) => void; } -const HexInput = (props: Partial) => { - const { color, onChange }: Props = { - color: "", - onChange: () => ({}), - ...props, - }; +const HexInput = ({ color = "", onChange = () => ({}) }: Partial) => { const [value, setValue] = useState(escape(color)); // Trigger `onChange` handler only if the input value is a valid HEX-color @@ -42,14 +37,18 @@ const HexInput = (props: Partial) => { }, [color]); // Spread operator replacement to get rid of the polyfill (saves 150 bytes gzipped) - const inputProps = Object.assign({}, props, { - color: null, // do not add `color` attr to `input`-tag - value, - maxLength: 6, - spellCheck: "false", // the element should not be checked for spelling errors - onChange: handleChange, - onBlur: handleBlur, - }); + const inputProps = Object.assign( + {}, + { color, onChange }, + { + color: null, // do not add `color` attr to `input`-tag + value, + maxLength: 6, + spellCheck: "false", // the element should not be checked for spelling errors + onChange: handleChange, + onBlur: handleBlur, + } + ); return React.createElement("input", inputProps); }; From 50c5ba5d713ee32974a7b930fddb4b8eb419abba Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 25 Aug 2020 22:43:34 +0100 Subject: [PATCH 25/29] fix: Corrected HexInput --- src/components/HexInput.tsx | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/components/HexInput.tsx b/src/components/HexInput.tsx index 63e152f8..e62675c5 100644 --- a/src/components/HexInput.tsx +++ b/src/components/HexInput.tsx @@ -10,7 +10,8 @@ interface Props { onChange: (newColor: string) => void; } -const HexInput = ({ color = "", onChange = () => ({}) }: Partial) => { +const HexInput = (props: Partial) => { + const { color = "", onChange } = props; const [value, setValue] = useState(escape(color)); // Trigger `onChange` handler only if the input value is a valid HEX-color @@ -18,7 +19,7 @@ const HexInput = ({ color = "", onChange = () => ({}) }: Partial) => { (e) => { const inputValue = escape(e.target.value); setValue(inputValue); - if (validHex(inputValue)) onChange("#" + inputValue); + if (onChange !== undefined && validHex(inputValue)) onChange("#" + inputValue); }, [onChange] ); @@ -37,18 +38,14 @@ const HexInput = ({ color = "", onChange = () => ({}) }: Partial) => { }, [color]); // Spread operator replacement to get rid of the polyfill (saves 150 bytes gzipped) - const inputProps = Object.assign( - {}, - { color, onChange }, - { - color: null, // do not add `color` attr to `input`-tag - value, - maxLength: 6, - spellCheck: "false", // the element should not be checked for spelling errors - onChange: handleChange, - onBlur: handleBlur, - } - ); + const inputProps = Object.assign({}, props, { + color: null, // do not add `color` attr to `input`-tag + value, + maxLength: 6, + spellCheck: "false", // the element should not be checked for spelling errors + onChange: handleChange, + onBlur: handleBlur, + }); return React.createElement("input", inputProps); }; From 5268d9e726694e9d86cbbab1500295948aed41b3 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 25 Aug 2020 22:45:55 +0100 Subject: [PATCH 26/29] fix(props): Making props optional again after HOC removal --- src/components/ColorPicker.tsx | 4 ++-- src/packages/hex.tsx | 2 +- src/packages/hsl.tsx | 2 +- src/packages/hslString.tsx | 2 +- src/packages/hsv.tsx | 2 +- src/packages/rgb.tsx | 2 +- src/packages/rgbString.tsx | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index c9070f3d..c9ae021b 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -8,12 +8,12 @@ import { ColorModel, HSV, ColorPickerBaseProps, AnyColor } from "../types"; import { equalColorObjects } from "../utils/compare"; import formatClassName from "../utils/formatClassName"; -interface Props extends ColorPickerBaseProps { +interface Props extends Partial> { colorModel: ColorModel; } const ColorPicker = ({ - className, + className = "", colorModel, color = colorModel.defaultColor, onChange, diff --git a/src/packages/hex.tsx b/src/packages/hex.tsx index e458c7e1..0ff7831c 100644 --- a/src/packages/hex.tsx +++ b/src/packages/hex.tsx @@ -12,7 +12,7 @@ const colorModel: ColorModel = { equal: equalHex, }; -const HexColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( +const HexColorPicker = (props: Partial>): JSX.Element => ( ); diff --git a/src/packages/hsl.tsx b/src/packages/hsl.tsx index fb5ba558..43cfea98 100644 --- a/src/packages/hsl.tsx +++ b/src/packages/hsl.tsx @@ -12,7 +12,7 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HslColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( +const HslColorPicker = (props: Partial>): JSX.Element => ( ); diff --git a/src/packages/hslString.tsx b/src/packages/hslString.tsx index cfa6ff75..9feed5cd 100644 --- a/src/packages/hslString.tsx +++ b/src/packages/hslString.tsx @@ -12,7 +12,7 @@ const colorModel: ColorModel = { equal: equalColorString, }; -const HslStringColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( +const HslStringColorPicker = (props: Partial>): JSX.Element => ( ); diff --git a/src/packages/hsv.tsx b/src/packages/hsv.tsx index b5c90a2a..59444b0e 100644 --- a/src/packages/hsv.tsx +++ b/src/packages/hsv.tsx @@ -11,7 +11,7 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const HsvColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( +const HsvColorPicker = (props: Partial>): JSX.Element => ( ); diff --git a/src/packages/rgb.tsx b/src/packages/rgb.tsx index e64e8b42..ee49a48f 100644 --- a/src/packages/rgb.tsx +++ b/src/packages/rgb.tsx @@ -12,7 +12,7 @@ const colorModel: ColorModel = { equal: equalColorObjects, }; -const RgbColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( +const RgbColorPicker = (props: Partial>): JSX.Element => ( ); diff --git a/src/packages/rgbString.tsx b/src/packages/rgbString.tsx index 81879d37..fc528b2e 100644 --- a/src/packages/rgbString.tsx +++ b/src/packages/rgbString.tsx @@ -12,7 +12,7 @@ const colorModel: ColorModel = { equal: equalColorString, }; -const RgbStringColorPicker = (props: ColorPickerBaseProps): JSX.Element => ( +const RgbStringColorPicker = (props: Partial>): JSX.Element => ( ); From 7c4a3959ea1678b2cad8f4034832485c0aee68aa Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Wed, 26 Aug 2020 01:10:44 +0100 Subject: [PATCH 27/29] refactor: Moved packages, updated build process --- build-packages.js | 75 ---------------------------- build-packages.mjs | 86 ++++++++++++++++++++++++++++++++ package.json | 7 +-- src/HexInput.ts | 2 + src/{packages => }/hex.tsx | 8 +-- src/{packages => }/hsl.tsx | 8 +-- src/{packages => }/hslString.tsx | 8 +-- src/{packages => }/hsv.tsx | 6 +-- src/packages/HexInput.ts | 2 - src/{packages => }/rgb.tsx | 8 +-- src/{packages => }/rgbString.tsx | 8 +-- tests/components.test.js | 4 +- 12 files changed, 117 insertions(+), 105 deletions(-) delete mode 100644 build-packages.js create mode 100644 build-packages.mjs create mode 100644 src/HexInput.ts rename src/{packages => }/hex.tsx (60%) rename src/{packages => }/hsl.tsx (60%) rename src/{packages => }/hslString.tsx (61%) rename src/{packages => }/hsv.tsx (67%) delete mode 100644 src/packages/HexInput.ts rename src/{packages => }/rgb.tsx (60%) rename src/{packages => }/rgbString.tsx (61%) diff --git a/build-packages.js b/build-packages.js deleted file mode 100644 index aadaac4f..00000000 --- a/build-packages.js +++ /dev/null @@ -1,75 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const del = require("del"); -const util = require("util"); -const { kebabCase, map } = require("lodash"); -const { peerDependencies } = require("./package.json"); - -// Convert NodeJS methods to promises in order to use them with `await` statement -const exec = util.promisify(require("child_process").exec); -const writeFile = util.promisify(fs.writeFile); -const makeDir = util.promisify(fs.mkdir); - -// Read available package sources from the dir -const entryDirPath = path.join(__dirname, "src/packages"); - -fs.readdir(entryDirPath, async (e, files) => { - // Bundles a package asynchronously - const bundlePackage = async (file) => { - const { name } = path.parse(file); - const isMainPackage = name === "hex"; - const outputDirPath = path.join(__dirname, isMainPackage ? "dist" : name); - const manifestPath = path.join(outputDirPath, `package.json`); - const bundlerPath = path.join(__dirname, "node_modules/.bin/microbundle"); - - // Format a package name according to NPM's naming guide - // https://docs.npmjs.com/files/package.json#name - const packageName = `react-colorful-${kebabCase(name)}`; - - // Delete the previous package version if exists - await del(outputDirPath); - - if (!isMainPackage) { - // Create `package.json` - var manifestCode = JSON.stringify({ - name: packageName, - private: true, - main: "index.js", - module: "index.module.js", - esmodule: "index.esmodule.js", - "umd:main": "index.umd.js", - source: `../src/packages/${file}`, - types: "index.d.ts", - peerDependencies, - }); - - await makeDir(outputDirPath); - await writeFile(manifestPath, manifestCode, "utf8"); - } - - // Bundler options - const args = { - name: packageName, - cwd: isMainPackage ? __dirname : outputDirPath, - output: `${outputDirPath}/index.js`, - jsx: "React.createElement", - "css-modules": "true", - tsconfig: "tsconfig.build.json", - }; - - // Format CLI arguments string - // `{ "a": "b" }` => "--key value" - const argsString = map(args, (value, key) => `--${key} ${value}`).join(" "); - - // Run microbundle - const { stdout } = await exec(`${bundlerPath} ${argsString}`); - console.log(stdout); - }; - - console.log(`⚙️ Building ${files.length} packages...`); - - // Process all packages in parallel - await Promise.all(files.map(bundlePackage)); - - console.log(`🎺 All packages are built`); -}); diff --git a/build-packages.mjs b/build-packages.mjs new file mode 100644 index 00000000..91b90df9 --- /dev/null +++ b/build-packages.mjs @@ -0,0 +1,86 @@ +import fs from "fs"; +import path from "path"; +import del from "del"; +import util from "util"; +import lodash from "lodash"; +const { kebabCase, map } = lodash; +import childProcess from "child_process"; +import pkg from "./package.json"; +const { peerDependencies } = pkg; + +// Convert NodeJS methods to promises in order to use them with `await` statement +const exec = util.promisify(childProcess.exec); +const writeFile = util.promisify(fs.writeFile); +const makeDir = util.promisify(fs.mkdir); + +// Read available package sources from the dir +const modulesArray = [ + "src/hex.tsx", + "src/HexInput.ts", + "src/hsl.tsx", + "src/hslString.tsx", + "src/hsv.tsx", + "src/rgb.tsx", + "src/rgbString.tsx", +]; + +const __dirname = path.resolve(); + +// Bundles a package asynchronously +const bundlePackage = async (file) => { + const { name } = path.parse(file); + const isMainPackage = name === "hex"; + const outputDirPath = path.join(__dirname, isMainPackage ? "dist" : name); + const manifestPath = path.join(outputDirPath, `package.json`); + const bundlerPath = path.join(__dirname, "node_modules/.bin/microbundle"); + + // Format a package name according to NPM's naming guide + // https://docs.npmjs.com/files/package.json#name + const packageName = `react-colorful-${kebabCase(name)}`; + + // Delete the previous package version if exists + await del(outputDirPath); + + if (!isMainPackage) { + // Create `package.json` + const manifestCode = JSON.stringify({ + name: packageName, + private: true, + main: "index.js", + module: "index.module.js", + esmodule: "index.esmodule.js", + "umd:main": "index.umd.js", + source: `../${file}`, + types: `${name}.d.ts`, + peerDependencies, + }); + + await makeDir(outputDirPath); + await writeFile(manifestPath, manifestCode); + } + + // Bundler options + const args = { + name: packageName, + cwd: isMainPackage ? __dirname : outputDirPath, + output: `${outputDirPath}/index.js`, + jsx: "React.createElement", + "css-modules": "true", + tsconfig: "tsconfig.build.json", + }; + + // Format CLI arguments string + // `{ "a": "b" }` => "--key value" + const argsString = map(args, (value, key) => `--${key} ${value}`).join(" "); + + // Run microbundle + const { stdout } = await exec(`${bundlerPath} ${argsString}`); + console.log(stdout); +}; + +console.log(`⚙️ Building ${modulesArray.length} packages...`); + +// Process all packages in parallel +await Promise.all(modulesArray.map(bundlePackage)); + +console.log(`🎺 All packages are built`); diff --git a/package.json b/package.json index 45ccf637..3e1d6ab5 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,17 @@ "name": "react-colorful", "version": "2.2.1", "description": "A tiny color picker component for modern React apps", - "source": "src/packages/hex.tsx", + "source": "src/hex.tsx", "main": "dist/index.js", "module": "dist/index.module.js", "esmodule": "dist/index.esmodule.js", "umd:main": "dist/index.umd.js", - "types": "dist/packages/hex.d.ts", + "types": "dist/hex.d.ts", "scripts": { "lint": "eslint src/**/*.{ts,tsx} demo/src/**/*.js", "size": "npm run build && size-limit", "test": "jest tests", - "build": "node ./build-packages.js", + "build": "node --experimental-json-modules ./build-packages.mjs", "prepublishOnly": "npm run build", "start-demo": "parcel demo/src/index.html --out-dir demo/dist --open", "build-demo": "del-cli 'demo/dist/*' && parcel build demo/src/index.html --out-dir demo/dist --public-url /react-colorful/", @@ -100,6 +100,7 @@ "@types/react": "^16.9.46", "@typescript-eslint/eslint-plugin": "^3.9.1", "@typescript-eslint/parser": "^3.9.1", + "del": "^5.1.0", "del-cli": "^3.0.1", "eslint": "^7.5.0", "eslint-config-prettier": "^6.11.0", diff --git a/src/HexInput.ts b/src/HexInput.ts new file mode 100644 index 00000000..05666ad6 --- /dev/null +++ b/src/HexInput.ts @@ -0,0 +1,2 @@ +import HexInput from "./components/HexInput"; +export default HexInput; diff --git a/src/packages/hex.tsx b/src/hex.tsx similarity index 60% rename from src/packages/hex.tsx rename to src/hex.tsx index 0ff7831c..b713e0ac 100644 --- a/src/packages/hex.tsx +++ b/src/hex.tsx @@ -1,9 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import { ColorModel, ColorPickerBaseProps } from "../types"; -import { equalHex } from "../utils/compare"; -import { hexToHsv, hsvToHex } from "../utils/convert"; +import ColorPicker from "./components/ColorPicker"; +import { ColorModel, ColorPickerBaseProps } from "./types"; +import { equalHex } from "./utils/compare"; +import { hexToHsv, hsvToHex } from "./utils/convert"; const colorModel: ColorModel = { defaultColor: "000", diff --git a/src/packages/hsl.tsx b/src/hsl.tsx similarity index 60% rename from src/packages/hsl.tsx rename to src/hsl.tsx index 43cfea98..cf95f888 100644 --- a/src/packages/hsl.tsx +++ b/src/hsl.tsx @@ -1,9 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import { ColorModel, ColorPickerBaseProps, HSL } from "../types"; -import { equalColorObjects } from "../utils/compare"; -import { hslToHsv, hsvToHsl } from "../utils/convert"; +import ColorPicker from "./components/ColorPicker"; +import { ColorModel, ColorPickerBaseProps, HSL } from "./types"; +import { equalColorObjects } from "./utils/compare"; +import { hslToHsv, hsvToHsl } from "./utils/convert"; const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, l: 0 }, diff --git a/src/packages/hslString.tsx b/src/hslString.tsx similarity index 61% rename from src/packages/hslString.tsx rename to src/hslString.tsx index 9feed5cd..1233cc01 100644 --- a/src/packages/hslString.tsx +++ b/src/hslString.tsx @@ -1,9 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import { ColorModel, ColorPickerBaseProps } from "../types"; -import { equalColorString } from "../utils/compare"; -import { hslStringToHsv, hsvToHslString } from "../utils/convert"; +import ColorPicker from "./components/ColorPicker"; +import { ColorModel, ColorPickerBaseProps } from "./types"; +import { equalColorString } from "./utils/compare"; +import { hslStringToHsv, hsvToHslString } from "./utils/convert"; const colorModel: ColorModel = { defaultColor: "hsl(0, 0%, 0%)", diff --git a/src/packages/hsv.tsx b/src/hsv.tsx similarity index 67% rename from src/packages/hsv.tsx rename to src/hsv.tsx index 59444b0e..4466ccb8 100644 --- a/src/packages/hsv.tsx +++ b/src/hsv.tsx @@ -1,8 +1,8 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import { ColorModel, ColorPickerBaseProps, HSV } from "../types"; -import { equalColorObjects } from "../utils/compare"; +import ColorPicker from "./components/ColorPicker"; +import { ColorModel, ColorPickerBaseProps, HSV } from "./types"; +import { equalColorObjects } from "./utils/compare"; const colorModel: ColorModel = { defaultColor: { h: 0, s: 0, v: 0 }, diff --git a/src/packages/HexInput.ts b/src/packages/HexInput.ts deleted file mode 100644 index 033a43e4..00000000 --- a/src/packages/HexInput.ts +++ /dev/null @@ -1,2 +0,0 @@ -import HexInput from "../components/HexInput"; -export default HexInput; diff --git a/src/packages/rgb.tsx b/src/rgb.tsx similarity index 60% rename from src/packages/rgb.tsx rename to src/rgb.tsx index ee49a48f..a1885af8 100644 --- a/src/packages/rgb.tsx +++ b/src/rgb.tsx @@ -1,9 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import { ColorModel, ColorPickerBaseProps, RGB } from "../types"; -import { equalColorObjects } from "../utils/compare"; -import { rgbToHsv, hsvToRgb } from "../utils/convert"; +import ColorPicker from "./components/ColorPicker"; +import { ColorModel, ColorPickerBaseProps, RGB } from "./types"; +import { equalColorObjects } from "./utils/compare"; +import { rgbToHsv, hsvToRgb } from "./utils/convert"; const colorModel: ColorModel = { defaultColor: { r: 0, g: 0, b: 0 }, diff --git a/src/packages/rgbString.tsx b/src/rgbString.tsx similarity index 61% rename from src/packages/rgbString.tsx rename to src/rgbString.tsx index fc528b2e..1fdde00c 100644 --- a/src/packages/rgbString.tsx +++ b/src/rgbString.tsx @@ -1,9 +1,9 @@ import React from "react"; -import ColorPicker from "../components/ColorPicker"; -import { ColorModel, ColorPickerBaseProps } from "../types"; -import { equalColorString } from "../utils/compare"; -import { rgbStringToHsv, hsvToRgbString } from "../utils/convert"; +import ColorPicker from "./components/ColorPicker"; +import { ColorModel, ColorPickerBaseProps } from "./types"; +import { equalColorString } from "./utils/compare"; +import { rgbStringToHsv, hsvToRgbString } from "./utils/convert"; const colorModel: ColorModel = { defaultColor: "rgb(0, 0, 0)", diff --git a/tests/components.test.js b/tests/components.test.js index ab3f7709..89d81bf4 100644 --- a/tests/components.test.js +++ b/tests/components.test.js @@ -1,7 +1,7 @@ import React from "react"; import { render, cleanup, fireEvent, waitFor } from "@testing-library/react"; -import ColorPicker from "../src/packages/hex"; -import HexInput from "../src/packages/HexInput"; +import ColorPicker from "../src/hex"; +import HexInput from "../src/HexInput"; afterEach(cleanup); From 427b210b1de284d5329be5b6a2234122fce990a7 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Wed, 26 Aug 2020 16:42:49 +0100 Subject: [PATCH 28/29] revert: Going back to CommonJS for build script --- build-packages.mjs => build-packages.js | 26 ++++++++++++------------- package.json | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) rename build-packages.mjs => build-packages.js (82%) diff --git a/build-packages.mjs b/build-packages.js similarity index 82% rename from build-packages.mjs rename to build-packages.js index 91b90df9..67e6c534 100644 --- a/build-packages.mjs +++ b/build-packages.js @@ -1,15 +1,12 @@ -import fs from "fs"; -import path from "path"; -import del from "del"; -import util from "util"; -import lodash from "lodash"; -const { kebabCase, map } = lodash; -import childProcess from "child_process"; -import pkg from "./package.json"; -const { peerDependencies } = pkg; +const fs = require("fs"); +const path = require("path"); +const del = require("del"); +const util = require("util"); +const { kebabCase, map } = require("lodash"); +const { peerDependencies } = require("./package.json"); // Convert NodeJS methods to promises in order to use them with `await` statement -const exec = util.promisify(childProcess.exec); +const exec = util.promisify(require("child_process").exec); const writeFile = util.promisify(fs.writeFile); const makeDir = util.promisify(fs.mkdir); @@ -24,8 +21,6 @@ const modulesArray = [ "src/rgbString.tsx", ]; -const __dirname = path.resolve(); - // Bundles a package asynchronously const bundlePackage = async (file) => { const { name } = path.parse(file); @@ -81,6 +76,9 @@ const bundlePackage = async (file) => { console.log(`⚙️ Building ${modulesArray.length} packages...`); // Process all packages in parallel -await Promise.all(modulesArray.map(bundlePackage)); +async function processPackages() { + await Promise.all(modulesArray.map(bundlePackage)); + console.log(`🎺 All packages are built`); +} -console.log(`🎺 All packages are built`); +processPackages(); diff --git a/package.json b/package.json index 3e1d6ab5..c6a5b6f2 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "lint": "eslint src/**/*.{ts,tsx} demo/src/**/*.js", "size": "npm run build && size-limit", "test": "jest tests", - "build": "node --experimental-json-modules ./build-packages.mjs", + "build": "node ./build-packages.js", "prepublishOnly": "npm run build", "start-demo": "parcel demo/src/index.html --out-dir demo/dist --open", "build-demo": "del-cli 'demo/dist/*' && parcel build demo/src/index.html --out-dir demo/dist --public-url /react-colorful/", From f9d17ac804e23901b5d007f17e14f26fb4c0f72f Mon Sep 17 00:00:00 2001 From: Vlad Shilov Date: Thu, 27 Aug 2020 14:51:26 +0300 Subject: [PATCH 29/29] Fix demo --- demo/src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/src/index.js b/demo/src/index.js index ab8bdbe1..5c95d34f 100644 --- a/demo/src/index.js +++ b/demo/src/index.js @@ -1,8 +1,8 @@ import React, { useState, useEffect, useCallback } from "react"; import ReactDOM from "react-dom"; -import ColorPicker from "../../src"; -import HexInput from "../../src/components/HexInput"; -import hexToRgb from "../../src/utils/hexToRgb"; +import ColorPicker from "../../src/hex"; +import HexInput from "../../src/HexInput"; +import { hexToRgb } from "../../src/utils/convert"; import styles from "./styles.css"; import useFaviconColor from "./hooks/useFaviconColor";