├── .gitignore ├── LICENSE ├── README.md ├── advanced_color_picker.zip ├── config ├── babel.config.js ├── eslint.config.js └── webpack.config.js ├── dist ├── img │ ├── github.jpg │ └── transparent.png ├── index.html └── js │ ├── cj-color-chunk-120.min.js │ ├── cj-color-chunk-120.min.js.LICENSE.txt │ ├── cj-color-chunk-606.min.js │ ├── cj-color.min.js │ └── cj-color.min.js.LICENSE.txt ├── package-lock.json ├── package.json ├── screenshot.jpg ├── single_screenshot.jpg └── src ├── js ├── components │ ├── buttons │ │ ├── button-group.js │ │ ├── button.js │ │ ├── copy-btn.js │ │ ├── range-buttons.js │ │ └── save-btn.js │ ├── grid.js │ ├── icon.js │ ├── inputs │ │ ├── input-field.js │ │ └── number-input.js │ ├── radio-menu.js │ ├── select-box.js │ ├── select-box │ │ └── select-color.js │ ├── sliders │ │ ├── drag-slider.js │ │ └── range-slider.js │ ├── toggle.js │ ├── wheel.js │ └── wrappers │ │ ├── input-wrap.js │ │ ├── panel.js │ │ ├── row.js │ │ ├── sortable.js │ │ └── wrapper.js ├── context.js ├── data │ ├── color-names.js │ ├── defaults.js │ └── presets.js ├── error.js ├── hoc │ ├── draggable.js │ ├── scrollable.js │ └── with-context.js ├── index.js ├── loader.js ├── module.js ├── module │ ├── container.js │ ├── editor.js │ ├── editor │ │ ├── controls.js │ │ ├── controls │ │ │ ├── color-controls.js │ │ │ ├── color-controls │ │ │ │ ├── color-buttons.js │ │ │ │ ├── color-fields.js │ │ │ │ ├── color-fields │ │ │ │ │ └── color-inputs.js │ │ │ │ ├── color-list.js │ │ │ │ ├── color-palette.js │ │ │ │ └── color-presets.js │ │ │ ├── gradient-controls.js │ │ │ └── gradient-controls │ │ │ │ ├── gradient-switcher.js │ │ │ │ └── radial-controls.js │ │ ├── footer.js │ │ ├── footer │ │ │ └── user-input.js │ │ ├── header.js │ │ ├── header │ │ │ ├── strip.js │ │ │ └── strip │ │ │ │ ├── color-point.js │ │ │ │ └── hint-point.js │ │ ├── presets.js │ │ ├── presets │ │ │ ├── preset-items.js │ │ │ └── preset-items │ │ │ │ ├── delete-preset.js │ │ │ │ └── preset.js │ │ ├── sidepanels.js │ │ └── sidepanels │ │ │ ├── hints.js │ │ │ ├── hints │ │ │ └── hint-pair.js │ │ │ └── preview.js │ └── full-preview.js ├── settings.js └── utils │ ├── colors.js │ ├── data.js │ ├── editor.js │ ├── global.js │ ├── gradients.js │ ├── hsl.js │ ├── output.js │ ├── presets.js │ ├── regexp.js │ └── utilities.js └── scss ├── editor.scss └── swatch.scss /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_STORE -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jason McElwaine 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Color Picker 2 | Harnessing the full power of CSS Gradients 3 | (one of the most advanced color pickers on the planet. fight me) 4 | 5 | ![Screenshot of the Color Picker Editor in Full Mode](/screenshot.jpg) 6 | 7 | ## Description 8 | 9 | Advanced Color Picker includes full support for modern CSS Gradients, with the ability to translate any valid CSS Gradient into editable controls. 10 | 11 | ## Features 12 | 13 | * **Stacked Gradients** - Bleed semi-transparent gradients into one another 14 | * **Color Hints** - Change the midpoint transition point between colors 15 | * **Pixel-based units** - Set positions to percentage or pixel-based values 16 | * **Repeating Gradients** - Create interesting patterns with pixel-based units 17 | * **Conic Gradients** - Experiment with conic gradients supported in Chrome & Safari 18 | * **Simple Editor Mode** - Can be used for non-gradient editing (text-color, etc.) via "single" mode 19 | * **Copy/Paste Gradients** - Copy any gradient from the web and paste it into the editor (it's like magic) 20 | 21 | ## Getting Started 22 | 23 | [Download](https://github.com/CodingJack/Advanced-Color-Picker/raw/master/advanced_color_picker.zip) the plugin and copy the files inside the "js" folder to your site. Then add the main script to your web page, setup an input field to be used for the swatch, and "init" the plugin with your custom settings. 24 | 25 | ## Basic Setup & Options 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | ```js 36 | // initial call with custom settings and their defaults 37 | window.advColorPicker( { 38 | // "full" = all controls, "single" = only color controls (no gradients) 39 | mode: 'full', 40 | 41 | // the size of the color picker swatches 42 | size: 24, 43 | 44 | // the color picker swatch skin, "classic" or "light" 45 | skin: 'classic', 46 | 47 | // optional color for the modal background 48 | modalBgColor: 'rgba(0,0,0,0.5)', 49 | 50 | // optional id attribute to apply to the editor's outermost wrapper 51 | editorId: null, 52 | 53 | // allow multi-color stops in output 54 | // multi-color stops allow for condensed output but are not supported in Edge 55 | multiStops: true, 56 | 57 | // allow conic gradients (only supported in webkit browsers) 58 | conic: true, 59 | 60 | // show a warning note for conic gradients (if conic is enabled) 61 | conicNote: false, 62 | 63 | // show the bar at the bottom of the screen displaying the final output value 64 | outputBar: false, 65 | 66 | // set the value of your input when a color is changed 67 | onColorChange: ( input, color ) => input.value = color, 68 | 69 | // your default and/or custom color presets 70 | colorPresets: { defaults: [], custom: [] }, 71 | 72 | // your default and/or gradient presets 73 | gradientPresets: { defaults: [], custom: [] }, 74 | 75 | // your save/delete preset callback function 76 | onSaveDeletePreset, 77 | } ); 78 | ``` 79 | 80 | ## data-attr options for input fields 81 | * **type** - "hidden" or "text" required 82 | * **class** - must match the "inputClass" const inside the index.js source file (currently: "cj-colorpicker") 83 | * **value** - any valid CSS color (an empty value will translate to "transparent") 84 | * **data-mode** - "single" (only color controls) or "full" (colors + gradient controls) - default: "full" 85 | * **data-size** - the width/height of the swatch - default: "24" 86 | * **data-skin** - "classic" or "light", the swatch skin - default: "classic" 87 | ```html 88 | 96 | ``` 97 | 98 | ## Example "onColorChange" callback 99 | ```js 100 | const onColorChange = ( input, color ) => input.value = color; 101 | ``` 102 | 103 | ## Example "onSaveDeletePreset" callback 104 | ```js 105 | const onSaveDeletePreset = ( { 106 | action, // "save" or "delete" 107 | groupChanged, // "color" or "gradient" 108 | colorPresets, // the current custom color presets array 109 | gradientPresets, // the current custom gradient presets array 110 | } ) => { 111 | // example saving to local storage 112 | window.localStorage.setItem( 'presets', JSON.stringify( { 113 | colorPresets, 114 | gradientPresets, 115 | })); 116 | }; 117 | ``` 118 | 119 | ## Editing JS/SCSS source files 120 | ``` 121 | npm install 122 | npm run watch 123 | npm run build 124 | ``` 125 | 126 | ## Built With / Technology Used 127 | 128 | * [React](https://www.npmjs.com/package/react) 129 | * [SASS](https://www.npmjs.com/package/sass) 130 | * [Babel](https://www.npmjs.com/package/@babel/core) 131 | * [Webpack](https://www.npmjs.com/package/webpack) 132 | * [ESLint](https://www.npmjs.com/package/eslint) 133 | * [core-js](https://www.npmjs.com/package/core-js) 134 | * [array-move](https://www.npmjs.com/package/array-move) 135 | * [React Sortable HOC](https://www.npmjs.com/package/react-sortable-hoc) 136 | * [Material Icons](https://www.npmjs.com/package/material-icons) 137 | 138 | ## Authors 139 | 140 | * **Jason McElwaine** - *Initial work* 141 | 142 | ## License 143 | 144 | * The original work in this project is licensed under [MIT](https://opensource.org/licenses/MIT) 145 | * All dependencies and cited technology above excluding Material Icons is licensed under [MIT](https://opensource.org/licenses/MIT) 146 | * [Material Icons](https://www.npmjs.com/package/material-icons) is licensed under [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) 147 | 148 | ## Additional Notes 149 | 150 | * If used in cases where all browsers must be accounted for, set the "multiStops" and "conic" options to false. 151 | * The APP does not automatically write values to the corresponding input field (intentionally). So the init settings should always include an "onColorChange" callback function. 152 | * Pixel based units for positioning and radial sizes have a maximum value of 800px in order to translate them properly into the editor visually. 153 | * drag the mini-preview to dynamically change radial and conic gradient positioning 154 | 155 | ## Single Mode 156 | 157 | * Where the editor is restricted to single colors only (for text color, etc.) 158 | 159 | ![Screenshot of the Color Picker Editor in Single Mode](/single_screenshot.jpg) 160 | -------------------------------------------------------------------------------- /advanced_color_picker.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingJack/Advanced-Color-Picker/1efe6d0a51a2ccdb1be2c091acf0e7c788b672d0/advanced_color_picker.zip -------------------------------------------------------------------------------- /config/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | [ 3 | '@babel/preset-env', 4 | { 5 | targets: { 6 | browsers: ['last 2 versions', 'safari >= 7'], 7 | }, 8 | useBuiltIns: 'usage', 9 | corejs: 3, 10 | }, 11 | '@babel/preset-react', 12 | ], 13 | ]; 14 | const plugins = [ 15 | '@babel/plugin-proposal-class-properties', 16 | '@babel/plugin-transform-react-jsx', 17 | ]; 18 | 19 | module.exports = { presets, plugins }; 20 | -------------------------------------------------------------------------------- /config/eslint.config.js: -------------------------------------------------------------------------------- 1 | const path = require( 'path' ); 2 | const dir = path.resolve( __dirname, '' ); 3 | 4 | module.exports = { 5 | overrideConfig: { 6 | env: { 7 | browser: true, 8 | es6: true, 9 | }, 10 | plugins: [ 11 | 'react', 12 | 'jsx-a11y', 13 | ], 14 | settings: { 15 | react: { 16 | version: 'detect', 17 | }, 18 | }, 19 | extends: [ 20 | 'eslint:recommended', 21 | 'plugin:react/recommended', 22 | 'plugin:jsx-a11y/recommended', 23 | ], 24 | globals: { 25 | require: 'readonly', 26 | ReactDOM: 'readonly', 27 | __webpack_public_path__: 'writable', 28 | }, 29 | parser: '@babel/eslint-parser', 30 | parserOptions: { 31 | sourceType: 'module', 32 | ecmaFeatures: { 33 | ecmaVersion: 6, 34 | impliedStrict: true, 35 | jsx: true, 36 | }, 37 | babelOptions: { 38 | configFile: `${ dir }/babel.config.js`, 39 | }, 40 | requireConfigFile: false, 41 | }, 42 | rules: { 43 | 'no-unused-vars': 'error', 44 | 'react/jsx-uses-react': 'error', 45 | 'react/jsx-uses-vars': 'error', 46 | 'no-cond-assign': 'error', 47 | 'no-template-curly-in-string': 'error', 48 | 'no-eval': 'error', 49 | 'no-floating-decimal': 'error', 50 | 'no-implicit-globals': 'error', 51 | 'no-implied-eval': 'error', 52 | 'no-lone-blocks': 'error', 53 | 'no-multi-spaces': 'error', 54 | 'no-multi-str': 'error', 55 | 'no-new': 'error', 56 | 'no-new-func': 'error', 57 | 'no-new-wrappers': 'error', 58 | 'no-param-reassign': 'error', 59 | 'no-return-assign': 'error', 60 | 'no-script-url': 'error', 61 | 'no-self-compare': 'error', 62 | 'no-sequences': 'error', 63 | 'no-unmodified-loop-condition': 'error', 64 | 'no-unused-expressions': 'error', 65 | 'no-useless-call': 'error', 66 | 'no-useless-concat': 'error', 67 | 'no-useless-return': 'error', 68 | radix: 'error', 69 | yoda: 'error', 70 | 'no-delete-var': 'error', 71 | 'no-label-var': 'error', 72 | 'no-useless-escape': 0, 73 | 'react/prop-types': 0, 74 | 'jsx-a11y/click-events-have-key-events': 0, 75 | 'jsx-a11y/no-static-element-interactions': 0, 76 | 'react/display-name': 0, 77 | 'react/jsx-no-target-blank': 0, 78 | }, 79 | }, 80 | }; 81 | -------------------------------------------------------------------------------- /config/webpack.config.js: -------------------------------------------------------------------------------- 1 | const ESLintPlugin = require( 'eslint-webpack-plugin' ); 2 | const TerserPlugin = require( 'terser-webpack-plugin' ); 3 | const resolve = require( 'path' ).resolve; 4 | const webpack = require( 'webpack' ); 5 | 6 | module.exports = env => { 7 | const plugins = [ 8 | new ESLintPlugin( require( './eslint.config.js' ) ), 9 | ]; 10 | const { WEBPACK_BUILD: production } = env; 11 | if( ! production ) { 12 | plugins.push( new webpack.SourceMapDevToolPlugin( {} ) ); 13 | } 14 | return { 15 | target: 'web', 16 | output: { 17 | path: resolve( 'dist' ), 18 | filename: 'cj-color.min.js', 19 | chunkFilename: 'cj-color-chunk-[id].min.js', 20 | publicPath: 'js/', 21 | }, 22 | resolve: { 23 | alias: { 24 | 'react-dom$': 'react-dom/profiling', 25 | 'scheduler/tracing': 'scheduler/tracing-profiling', 26 | }, 27 | }, 28 | module: { 29 | noParse: [ 30 | /benchmark/, 31 | ], 32 | rules: [ 33 | { 34 | test: /\.js$/, 35 | enforce: 'pre', 36 | exclude: /node_modules/, 37 | use: [ 38 | { 39 | loader: 'babel-loader', 40 | options: require( './babel.config.js' ), 41 | }, 42 | { 43 | loader: 'source-map-loader', 44 | options: {}, 45 | }, 46 | ], 47 | }, 48 | { 49 | test: /\.(s*)css$/, 50 | use: [ 51 | { 52 | loader: 'style-loader', 53 | options: { 54 | injectType: 'styleTag', 55 | }, 56 | }, 57 | { 58 | loader: 'css-loader', 59 | options: { 60 | sourceMap: true, 61 | }, 62 | }, 63 | { 64 | loader: 'sass-loader', 65 | options: { 66 | sourceMap: true, 67 | }, 68 | }, 69 | ], 70 | }, 71 | ], 72 | }, 73 | stats: 'error-details', 74 | optimization: { 75 | minimizer: [ 76 | new TerserPlugin( { 77 | terserOptions: { 78 | output: { 79 | comments: false, 80 | }, 81 | }, 82 | extractComments: true, 83 | } ), 84 | ], 85 | }, 86 | plugins, 87 | devtool: false, 88 | performance: { 89 | hints: false, 90 | maxEntrypointSize: 300000, 91 | maxAssetSize: 300000 92 | }, 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /dist/img/github.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingJack/Advanced-Color-Picker/1efe6d0a51a2ccdb1be2c091acf0e7c788b672d0/dist/img/github.jpg -------------------------------------------------------------------------------- /dist/img/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingJack/Advanced-Color-Picker/1efe6d0a51a2ccdb1be2c091acf0e7c788b672d0/dist/img/transparent.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 32 | 33 | 34 |
35 | 36 | Advanced Color Picker 37 | by CodingJack 38 |
39 | 40 | 41 | 55 | 65 |
66 |
67 | 68 | 69 | 70 | 71 | 160 | 161 | 165 | 168 | 169 | 170 | 188 | 189 | 190 | 206 | 207 | 212 | 229 | 230 | 231 | 238 | 239 | -------------------------------------------------------------------------------- /dist/js/cj-color-chunk-120.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * A better abstraction over CSS. 3 | * 4 | * @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present 5 | * @website https://github.com/cssinjs/jss 6 | * @license MIT 7 | */ 8 | 9 | /** @license React v16.13.1 10 | * react-is.production.min.js 11 | * 12 | * Copyright (c) Facebook, Inc. and its affiliates. 13 | * 14 | * This source code is licensed under the MIT license found in the 15 | * LICENSE file in the root directory of this source tree. 16 | */ 17 | -------------------------------------------------------------------------------- /dist/js/cj-color.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /** @license React v0.20.2 8 | * scheduler-tracing.profiling.min.js 9 | * 10 | * Copyright (c) Facebook, Inc. and its affiliates. 11 | * 12 | * This source code is licensed under the MIT license found in the 13 | * LICENSE file in the root directory of this source tree. 14 | */ 15 | 16 | /** @license React v0.20.2 17 | * scheduler.production.min.js 18 | * 19 | * Copyright (c) Facebook, Inc. and its affiliates. 20 | * 21 | * This source code is licensed under the MIT license found in the 22 | * LICENSE file in the root directory of this source tree. 23 | */ 24 | 25 | /** @license React v17.0.2 26 | * react-dom.profiling.min.js 27 | * 28 | * Copyright (c) Facebook, Inc. and its affiliates. 29 | * 30 | * This source code is licensed under the MIT license found in the 31 | * LICENSE file in the root directory of this source tree. 32 | */ 33 | 34 | /** @license React v17.0.2 35 | * react.production.min.js 36 | * 37 | * Copyright (c) Facebook, Inc. and its affiliates. 38 | * 39 | * This source code is licensed under the MIT license found in the 40 | * LICENSE file in the root directory of this source tree. 41 | */ 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advanced-color-picker", 3 | "version": "1.1.0", 4 | "description": "Advanced Color Picker", 5 | "author": "CodingJack", 6 | "license": "MIT", 7 | "keywords": [ 8 | "Color", 9 | "Gradient", 10 | "Color Picker" 11 | ], 12 | "homepage": "https://www.codingjack.com/advanced-color-picker", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/CodingJack/Advanced-Color-Picker" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/CodingJack/Advanced-Color-Picker", 19 | "email": "support@codingjack.com" 20 | }, 21 | "main": "index.js", 22 | "dependencies": { 23 | "array-move": "^3.0.1", 24 | "fix": "^0.0.6", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "react-sortable-hoc": "^2.0.0" 28 | }, 29 | "devDependencies": { 30 | "@babel/core": "^7.15.0", 31 | "@babel/eslint-parser": "^7.15.0", 32 | "@babel/plugin-proposal-class-properties": "^7.14.5", 33 | "@babel/plugin-transform-react-jsx": "^7.14.9", 34 | "@babel/preset-env": "^7.15.0", 35 | "@babel/preset-react": "^7.14.5", 36 | "@material-ui/core": "^4.12.3", 37 | "@material-ui/icons": "^4.11.2", 38 | "admin-bro": "^3.2.5", 39 | "babel-loader": "^8.2.2", 40 | "core-js": "^3.16.1", 41 | "css-loader": "^6.2.0", 42 | "eslint": "^7.32.0", 43 | "eslint-plugin-jsx-a11y": "^6.4.1", 44 | "eslint-plugin-react": "^7.24.0", 45 | "eslint-webpack-plugin": "^3.0.1", 46 | "express": "^4.17.1", 47 | "node-sass": "^6.0.1", 48 | "sass-loader": "^12.1.0", 49 | "source-map-loader": "^3.0.0", 50 | "style-loader": "^3.2.1", 51 | "terser-webpack-plugin": "^5.1.4", 52 | "webpack": "^5.49.0", 53 | "webpack-cli": "^4.7.2" 54 | }, 55 | "scripts": { 56 | "watch": "webpack --watch ./src/js/index.js --output-path ./dist/js --config ./config/webpack.config.js --mode=development", 57 | "build": "webpack ./src/js/index.js --output-path ./dist/js --config ./config/webpack.config.js --mode=production" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingJack/Advanced-Color-Picker/1efe6d0a51a2ccdb1be2c091acf0e7c788b672d0/screenshot.jpg -------------------------------------------------------------------------------- /single_screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingJack/Advanced-Color-Picker/1efe6d0a51a2ccdb1be2c091acf0e7c788b672d0/single_screenshot.jpg -------------------------------------------------------------------------------- /src/js/components/buttons/button-group.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Button from './button'; 3 | 4 | import { 5 | AppContext, 6 | } from '../../context'; 7 | 8 | const { 9 | memo, 10 | useContext, 11 | } = React; 12 | 13 | /* 14 | * @desc creates a group of buttons that act like radio inputs 15 | * @since 1.0.0 16 | */ 17 | const ButtonGroup = ({ slug, type, items, active, onChange }) => { 18 | const locale = useContext(AppContext); 19 | const { namespace } = locale; 20 | 21 | return ( 22 | 23 | { 24 | Object.keys(items).map(key => { 25 | return ( 26 |