├── .npmignore
├── example
├── .watchmanconfig
├── assets
│ ├── icon.png
│ └── splash.png
├── babel.config.js
├── .gitignore
├── .expo-shared
│ └── assets.json
├── tsconfig.json
├── app.json
├── package.json
├── metro.config.js
└── App.tsx
├── .gitignore
├── images
└── color-picker.png
├── src
├── icon.js
├── color-option.js
└── index.js
├── package.json
├── LICENSE
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 | example
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 |
--------------------------------------------------------------------------------
/example/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holmansv/react-native-color-palette/HEAD/example/assets/icon.png
--------------------------------------------------------------------------------
/images/color-picker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holmansv/react-native-color-palette/HEAD/images/color-picker.png
--------------------------------------------------------------------------------
/example/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holmansv/react-native-color-palette/HEAD/example/assets/splash.png
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 | web-report/
12 |
--------------------------------------------------------------------------------
/example/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "f9155ac790fd02fadcdeca367b02581c04a353aa6d5aa84409a59f6804c87acd": true,
3 | "89ed26367cdb9b771858e026f2eb95bfdb90e5ae943e716575327ec325f39c44": true
4 | }
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "jsx": "react-native",
5 | "lib": ["dom", "esnext"],
6 | "moduleResolution": "node",
7 | "noEmit": true,
8 | "skipLibCheck": true,
9 | "resolveJsonModule": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/icon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Text } from 'react-native'
4 |
5 | const getContrastColor = hex => parseInt(hex.substring(1), 16) > 0xffffff / 2 ? '#000000' : '#FFFFFF';
6 |
7 | const Icon = (props) => {
8 | const { icon, color } = props;
9 | if (icon) return icon;
10 | return ✔︎;
11 | }
12 |
13 | Icon.defaultProps = {
14 | icon: undefined
15 | }
16 |
17 | Icon.propTypes = {
18 | icon: PropTypes.node,
19 | color: PropTypes.string.isRequired,
20 | }
21 |
22 | export default Icon
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "Example",
4 | "slug": "example",
5 | "privacy": "public",
6 | "sdkVersion": "34.0.0",
7 | "platforms": [
8 | "ios",
9 | "android",
10 | "web"
11 | ],
12 | "version": "1.0.0",
13 | "orientation": "portrait",
14 | "icon": "./assets/icon.png",
15 | "splash": {
16 | "image": "./assets/splash.png",
17 | "resizeMode": "contain",
18 | "backgroundColor": "#ffffff"
19 | },
20 | "updates": {
21 | "fallbackToCacheTimeout": 0
22 | },
23 | "assetBundlePatterns": [
24 | "**/*"
25 | ],
26 | "ios": {
27 | "supportsTablet": true
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "expo": "^34.0.1",
12 | "react": "16.8.3",
13 | "react-dom": "^16.8.6",
14 | "react-native": "https://github.com/expo/react-native/archive/sdk-34.0.0.tar.gz",
15 | "react-native-color-palette": "file:..",
16 | "react-native-web": "^0.11.4"
17 | },
18 | "devDependencies": {
19 | "@types/react": "^16.8.23",
20 | "@types/react-native": "^0.57.65",
21 | "babel-preset-expo": "^6.0.0",
22 | "typescript": "^3.4.5"
23 | },
24 | "private": true
25 | }
26 |
--------------------------------------------------------------------------------
/example/metro.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const blacklist = require('metro-config/src/defaults/blacklist');
3 | const pak = require('../package.json');
4 | const escape = require('escape-string-regexp');
5 |
6 | const dependencies = Object.keys(pak.dependencies);
7 |
8 | module.exports = {
9 | projectRoot: __dirname,
10 | watchFolders: [path.resolve(__dirname, '..')],
11 |
12 | resolver: {
13 | blacklistRE: blacklist([
14 | new RegExp(
15 | `^${escape(path.resolve(__dirname, '..', 'node_modules'))}\\/.*$`
16 | ),
17 | new RegExp(
18 | `^${escape(
19 | path.resolve(__dirname, '..', 'docs', 'node_modules')
20 | )}\\/.*$`
21 | ),
22 | ]),
23 |
24 | providesModuleNodeModules: [
25 | 'react-native',
26 | 'react',
27 | 'prop-types',
28 | '@babel/runtime',
29 | ...dependencies,
30 | ],
31 | },
32 | };
--------------------------------------------------------------------------------
/example/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { StyleSheet, Text, View } from 'react-native';
3 | import ColorPalette from 'react-native-color-palette';
4 |
5 | export default function App() {
6 | const [selectedColor, setSelectedColor] = useState('#C0392B');
7 | return (
8 |
9 |
14 |
15 | {selectedColor}
16 |
17 |
18 | );
19 | }
20 |
21 | const styles = StyleSheet.create({
22 | container: {
23 | flex: 1,
24 | backgroundColor: '#fff',
25 | alignItems: 'center',
26 | justifyContent: 'center',
27 | },
28 | });
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-color-palette",
3 | "version": "2.2.0",
4 | "description": "A react native module for simple hex color selection",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/holmansv/react-native-color-palette.git"
12 | },
13 | "keywords": [
14 | "react",
15 | "react-native",
16 | "colors",
17 | "color-picker",
18 | "color-palette",
19 | "palette"
20 | ],
21 | "author": "Holman Strategic Ventures",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/holmansv/react-native-color-palette/issues"
25 | },
26 | "homepage": "https://github.com/holmansv/react-native-color-palette#readme",
27 | "dependencies": {},
28 | "devDependencies": {
29 | "@babel/runtime": "^7.2.0",
30 | "prop-types": "15.7.2"
31 | },
32 | "peerDependencies": {
33 | "react": "*",
34 | "react-native": "*"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 holmansv
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/color-option.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { TouchableOpacity, Dimensions, StyleSheet } from 'react-native'
4 |
5 | import Icon from './icon';
6 |
7 | const { width } = Dimensions.get('window');
8 |
9 | const ColorOption = (props) => {
10 | const { icon, color, isSelected, scaleToWindow, onColorChange } = props;
11 | let scaledWidth = width * .025;
12 | return (
13 | onColorChange(color)}
15 | style={[
16 | styles.colorOption,
17 | { backgroundColor: color },
18 | scaleToWindow && {
19 | width: width * .07,
20 | height: width * .07,
21 | marginHorizontal: scaledWidth,
22 | marginVertical: scaledWidth,
23 | borderRadius: scaledWidth * 2
24 | }
25 | ]}
26 | >
27 | {isSelected && }
28 |
29 | );
30 | }
31 |
32 | const styles = StyleSheet.create({
33 | colorOption: {
34 | borderWidth: 1,
35 | borderColor: 'rgba(0,0,0,0.2)',
36 | alignItems: 'center',
37 | justifyContent: 'center',
38 | width: 30,
39 | height: 30,
40 | marginHorizontal: 10,
41 | marginVertical: 10,
42 | borderRadius: 15,
43 | elevation: 5,
44 | shadowOffset: { width: 2, height: 2 },
45 | shadowColor: 'black',
46 | shadowOpacity: .25,
47 | }
48 | });
49 |
50 | ColorOption.propTypes = {
51 | icon: PropTypes.node,
52 | color: PropTypes.string.isRequired,
53 | isSelected: PropTypes.bool.isRequired,
54 | scaleToWindow: PropTypes.bool.isRequired,
55 | onColorChange: PropTypes.func.isRequired,
56 | }
57 |
58 | export default ColorOption;
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React, { useState, useEffect, Fragment, useCallback } from 'react';
3 | import { View, Text, StyleSheet } from 'react-native';
4 |
5 | import ColorOption from './color-option';
6 |
7 | const ColorPalette = (props) => {
8 | const {
9 | colors,
10 | defaultColor,
11 | icon,
12 | onChange,
13 | paletteStyles,
14 | scaleToWindow,
15 | title,
16 | titleStyles,
17 | value,
18 | } = props;
19 | const [color, setColor] = useState(value || defaultColor);
20 |
21 | useEffect(() => {
22 | value && setColor(value);
23 | }, [value]);
24 |
25 | const onColorChange = useCallback((color) => {
26 | setColor(color);
27 | onChange(color);
28 | }, [onChange]);
29 |
30 | return (
31 |
32 | {title}
33 |
34 | {colors.map((c) => (
35 |
43 | ))}
44 |
45 |
46 | );
47 | }
48 |
49 | const styles = StyleSheet.create({
50 | titleStyles: {
51 | color: 'black',
52 | },
53 | colorContainer: {
54 | flexDirection: 'row',
55 | flexWrap: 'wrap',
56 | alignItems: 'center',
57 | justifyContent: 'center'
58 | }
59 | });
60 |
61 | ColorPalette.defaultProps = {
62 | colors: [
63 | '#C0392B', '#E74C3C', '#9B59B6', '#8E44AD', '#2980B9', '#3498DB', '#1ABC9C',
64 | '#16A085', '#27AE60', '#2ECC71', '#F1C40F', '#F39C12', '#E67E22', '#D35400',
65 | '#FFFFFF', '#BDC3C7', '#95A5A6', '#7F8C8D', '#34495E', '#2C3E50', '#000000',
66 | ],
67 | defaultColor: null,
68 | onChange: () => { },
69 | paletteStyles: {},
70 | scaleToWindow: false,
71 | title: "Color Palette:",
72 | titleStyles: {},
73 | value: null,
74 | };
75 |
76 | ColorPalette.propTypes = {
77 | colors: PropTypes.arrayOf(PropTypes.string),
78 | title: PropTypes.string,
79 | onChange: PropTypes.func,
80 | defaultColor: PropTypes.string,
81 | value: PropTypes.string,
82 | paletteStyles: PropTypes.shape({})
83 | };
84 |
85 | export default ColorPalette;
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Color Palette.
2 |
3 | A react native module for simple hex color selection
4 |
5 | 
6 |
7 | * [x] Controlled and Uncontrolled implementations
8 | * [x] Simple to use
9 |
10 |
11 | ## Getting started
12 | Install the color picker
13 | ```
14 | npm install react-native-color-palette --save
15 | ```
16 |
17 | ```javascript
18 | import ColorPalette from 'react-native-color-palette'
19 |
20 | const UncontrolledColorPicker = () => (
21 | alert(`Color selected: ${color}`)}
23 | defaultColor={'#C0392B'}
24 | colors={['#C0392B', '#E74C3C', '#9B59B6', '#8E44AD', '#2980B9']}
25 | title={"Uncontrolled Color Palette:"}
26 | icon={
27 | ✔︎
28 | // Icon can just be text or ASCII
29 | }
30 | />
31 | )
32 |
33 | const ControlledColorPicker = () => {
34 | let selectedColor = '#C0392B';
35 | return (
36 | selectedColor = color}
38 | value={selectedColor}
39 | colors={['#C0392B', '#E74C3C', '#9B59B6', '#8E44AD', '#2980B9']}
40 | title={"Controlled Color Palette:"}
41 | icon={
42 |
43 | // React-Native-Vector-Icons Example
44 | }
45 | />)
46 | }
47 | ```
48 | Due to its Flexbox design, Color Palette will use the space you provide!
49 |
50 | ## API
51 | ### Props
52 |
53 | Color Palette accepts properties below.
54 |
55 | | Property | Type | Note |
56 | | --------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
57 | | `colors` | `Array` | Array of hex color strings for rendering. ex) ['#C0392B', '#E74C3C', '#9B59B6', '#8E44AD', '#2980B9'] |
58 | | `defaultColor` | `String` | Defines initial selected color in uncontrolled component. |
59 | | `value` | `String` | Defines selected color in controlled component. |
60 | | `paletteStyles` | `ViewStyle` | Styles passed to color palette container |
61 | | `onChange` | `Function` | Callback with color (HEX string) as argument called when user confirms color selection. |
62 | | `title` | `String` | Text to display at the top of the palette. |
63 | | `titleStyles` | `TextStyle` | Inherits the default react-native Text Styles |
64 | | `icon` | `Text` or `Icon` | Selector Text or Icon to be displayed in place of checkmark. |
65 | | `scaleToWindow` | `Bool` | This will automatically scale the palette to fit 6 per line and will scale up/down for iPads/ iPhones depending on window size |
66 |
--------------------------------------------------------------------------------