├── .gitignore
├── .travis.yml
├── README.md
├── jest.config.js
├── package.json
├── src
├── Palette.tsx
├── __mocks__
│ └── node-vibrant.ts
├── __tests__
│ ├── Palette.tsx
│ ├── __snapshots__
│ │ └── getPalette.ts.snap
│ └── getPalette.ts
├── getPalette.ts
├── index.ts
└── usePalette.tsx
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | coverage
4 | .rpt2_cache
5 | .rts2_cache_cjs
6 | .rts2_cache_es
7 | .rts2_cache_umd
8 | yarn-error.log
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | script:
5 | - 'npm run test:coverage'
6 | after_script:
7 | - 'cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js'
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # REACT PALETTE
2 |
3 | Extract prominent colors from an image
4 |
5 | [](https://travis-ci.org/leonardokl/react-palette)
6 | [](https://coveralls.io/github/leonardokl/react-palette?branch=master)
7 |
8 | ## Install
9 | ```
10 | npm i -S react-palette
11 | ```
12 |
13 | ## Usage
14 | ```jsx
15 | import Palette from 'react-palette';
16 | // In your render...
17 |
18 | {({ data, loading, error }) => (
19 |
20 | Text with the vibrant color
21 |
22 | )}
23 |
24 | ```
25 |
26 | ```jsx
27 | import { usePalette } from 'react-palette'
28 |
29 | const { data, loading, error } = usePalette(IMAGE_URL)
30 |
31 |
32 | Text with the vibrant color
33 |
34 | ```
35 |
36 | ## Palette callback example
37 | ```js
38 | {
39 | darkMuted: "#2a324b"
40 | darkVibrant: "#0e7a4b"
41 | lightMuted: "#9cceb7"
42 | lightVibrant: "#a4d4bc"
43 | muted: "#64aa8a"
44 | vibrant: "#b4d43c"
45 | }
46 | ```
47 |
48 | ## Notes
49 |
50 | That library was created using `node-vibrant` to extract the prominent colors.
51 |
52 | [https://github.com/akfish/node-vibrant](https://github.com/akfish/node-vibrant)
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | roots: ["/src"],
3 | transform: {
4 | "^.+\\.tsx?$": "ts-jest"
5 | }
6 | };
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-palette",
3 | "version": "1.0.2",
4 | "description": "",
5 | "main": "dist/react-palette.js",
6 | "umd:main": "dist/react-palette.umd.js",
7 | "module": "dist/react-palette.mjs",
8 | "browser": "dist/react-palette.umd.js",
9 | "types": "dist/index.d.ts",
10 | "scripts": {
11 | "test": "jest",
12 | "test:watch": "npm test -- --watch",
13 | "test:coverage": "npm test -- --coverage",
14 | "build": "microbundle",
15 | "preversion": "npm test && npm run build",
16 | "postversion": "git push && git push --tags && npm publish"
17 | },
18 | "keywords": [
19 | "react",
20 | "palette",
21 | "dominant color"
22 | ],
23 | "author": "Leonardo Luiz ",
24 | "license": "ISC",
25 | "repository": {
26 | "type": "git",
27 | "url": "git://github.com/leonardokl/react-palette.git"
28 | },
29 | "files": [
30 | "dist",
31 | "src"
32 | ],
33 | "peerDependencies": {
34 | "react": "^16.8.6",
35 | "react-dom": "^16.8.6"
36 | },
37 | "dependencies": {
38 | "lodash.camelcase": "^4.3.0",
39 | "lodash.invoke": "^4.5.2",
40 | "node-vibrant": "^3.1.3"
41 | },
42 | "devDependencies": {
43 | "@testing-library/react": "^8.0.1",
44 | "@types/jest": "^24.0.15",
45 | "@types/react": "^16.8.20",
46 | "coveralls": "^3.0.4",
47 | "jest": "^24.8.0",
48 | "microbundle": "^0.11.0",
49 | "react": "^16.8.6",
50 | "react-dom": "^16.8.6",
51 | "ts-jest": "^24.0.2"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Palette.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode } from "react";
2 | import { PaletteState, usePalette } from "./usePalette";
3 |
4 | export type PaletteProps = {
5 | src: string;
6 | children(palette: PaletteState): ReactNode;
7 | };
8 |
9 | export const Palette: React.FC = ({
10 | src,
11 | children
12 | }: PaletteProps) => {
13 | const palette = usePalette(src);
14 |
15 | return <>{children(palette)}>;
16 | };
17 |
--------------------------------------------------------------------------------
/src/__mocks__/node-vibrant.ts:
--------------------------------------------------------------------------------
1 | const Swatch = (hex) => ({
2 | getHex: () => hex
3 | })
4 |
5 | const palette = {
6 | DarkMuted: Swatch('#2a324b'),
7 | DarkVibrant: Swatch("#0e7a4b"),
8 | LightMuted: Swatch("#9cceb7"),
9 | LightVibrant: Swatch("#a4d4bc"),
10 | Muted: Swatch("#64aa8a"),
11 | Vibrant: Swatch("#b4d43c")
12 | }
13 |
14 | export default {
15 | from: () => ({
16 | getPalette: async () => palette
17 | })
18 | }
--------------------------------------------------------------------------------
/src/__tests__/Palette.tsx:
--------------------------------------------------------------------------------
1 | import { render, wait } from "@testing-library/react";
2 | import React from "react";
3 | import { Palette, getPalette } from "../";
4 |
5 | test("execute children with palette", async () => {
6 | const children = jest.fn(() => null);
7 | const src = "test";
8 | const palette = await getPalette(src);
9 |
10 | render();
11 |
12 | expect(children).toHaveBeenCalledWith({
13 | loading: true,
14 | error: undefined,
15 | data: {}
16 | });
17 |
18 | await wait();
19 |
20 | expect(children).toHaveBeenCalledWith({
21 | loading: false,
22 | error: undefined,
23 | data: palette
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/getPalette.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`return camelCased values 1`] = `
4 | Object {
5 | "darkMuted": "#2a324b",
6 | "darkVibrant": "#0e7a4b",
7 | "lightMuted": "#9cceb7",
8 | "lightVibrant": "#a4d4bc",
9 | "muted": "#64aa8a",
10 | "vibrant": "#b4d43c",
11 | }
12 | `;
13 |
--------------------------------------------------------------------------------
/src/__tests__/getPalette.ts:
--------------------------------------------------------------------------------
1 | import { getPalette } from "../";
2 |
3 | test("return camelCased values", async () => {
4 | const actual = await getPalette("test");
5 |
6 | expect(actual).toMatchSnapshot();
7 | });
8 |
--------------------------------------------------------------------------------
/src/getPalette.ts:
--------------------------------------------------------------------------------
1 | import Vibrant from "node-vibrant";
2 | import camelCase from "lodash.camelcase";
3 | import invoke from 'lodash.invoke';
4 |
5 | export type PaletteColors = {
6 | vibrant?: string;
7 | muted?: string;
8 | darkVibrant?: string;
9 | darkMuted?: string;
10 | lightVibrant?: string;
11 | lightMuted?: string;
12 | [name: string]: string | undefined;
13 | };
14 |
15 | export async function getPalette(src: string) {
16 | const palette = await Vibrant.from(src).getPalette();
17 | const setPaletteColor = (acc, paletteName) => ({
18 | ...acc,
19 | [camelCase(paletteName)]: invoke(palette, [paletteName, 'getHex'])
20 | });
21 |
22 | return Object.keys(palette).reduce(setPaletteColor, {});
23 | }
24 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./getPalette";
2 | export * from "./Palette";
3 | export { Palette as default } from "./Palette";
4 | export * from "./usePalette";
5 |
--------------------------------------------------------------------------------
/src/usePalette.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { getPalette, PaletteColors } from "./getPalette";
3 |
4 | export type PaletteState = {
5 | loading: boolean;
6 | error?: Error;
7 | data: PaletteColors;
8 | };
9 |
10 | const initialState: PaletteState = {
11 | loading: true,
12 | data: {},
13 | error: undefined,
14 | };
15 |
16 | function reducer(state: PaletteState, action): PaletteState {
17 | switch (action.type) {
18 | case "getPalette":
19 | return initialState;
20 | case "resolvePalette":
21 | return { ...state, data: action.payload, loading: false };
22 | case "rejectPalette":
23 | return { ...state, error: action.payload, loading: false };
24 | }
25 | }
26 |
27 | export function usePalette(src: string) {
28 | const [state, dispatch] = React.useReducer(reducer, initialState);
29 |
30 | React.useEffect(() => {
31 | dispatch({ type: "getPalette" });
32 |
33 | getPalette(src)
34 | .then((palette) => {
35 | dispatch({ type: "resolvePalette", payload: palette });
36 | })
37 | .catch((ex) => {
38 | dispatch({ type: "rejectPalette", payload: ex });
39 | });
40 | }, [src]);
41 |
42 | return state;
43 | }
44 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "jsx": "react",
5 | "target": "es5",
6 | "esModuleInterop": true
7 | },
8 | "exclude": ["src/__mocks__", "src/__tests__"]
9 | }
10 |
--------------------------------------------------------------------------------